Pourquoi n'avons-nous pas un constructeur virtuel en C++?
Pourquoi est-ce que C++ a pas un constructeur virtuel?
- Si le C++ n'ont constructeurs virtuels, comment voulez-vous utiliser?
virtual functions aid in dynamic binding -> which happens at run-time -> objects are created at run-time -> objects creation requires constructor
. Si cette ctor était virtuel, le chien serait de commencer à chasser sa queue (le chien étant le pauvre compilateur :p)
Vous devez vous connecter pour publier un commentaire.
L'entendre de la bouche des chevaux:).
De Bjarne Stroustrup C++ de Style et de la Technique FAQ
Pourquoi n'avons-nous pas des constructeurs virtuels?
L'entrée de la FAQ va donner le code pour un moyen de parvenir à cette fin sans un constructeur virtuel.
Fonctions virtuelles en fait fournissent le comportement polymorphique. C'est, lorsque vous travaillez avec un objet dont le type dynamique est différente de la statique (compilation) type avec laquelle il est appelé, il fournit le comportement qui est approprié pour le réelle type de l'objet au lieu de le type statique de l'objet.
Maintenant, essayez d'appliquer ce genre de comportement à un constructeur. Lorsque vous construisez un objet le type statique est toujours le même que le type d'objet depuis:
(Bjarne Stroustup (P424 Le Langage de Programmation C++ SE))
Contrairement aux langages orientés objet tels que Smalltalk ou Python, où le constructeur est une méthode virtuelle de l'objet représentant la classe (ce qui signifie que vous n'avez pas besoin du GoF abstrait modèle de fabrique, que vous pouvez passer de l'objet représentant la classe autour au lieu de faire votre propre), le C++ est une classe de langue, et de ne pas les objets qui représentent tout de la langue de constructions. La classe n'existe pas comme un objet au moment de l'exécution, de sorte que vous ne pouvez pas appeler une méthode virtuelle sur elle.
Cela concorde avec l' "vous n'avez pas à payer pour ce que vous n'utilisez pas de "philosophie", bien que chaque grand projet C++ que j'ai vu a fini par mettre en place une certaine forme de résumé de l'usine ou de réflexion.
deux raisons je pense:
Raison technique
L'objet existe seulement après que le constructeur se termine.Pour que le constructeur à être distribué à l'aide de la table virtuelle , il y a un objet existant avec un pointeur vers la table virtuelle , mais comment un pointeur vers la table virtuelle existe pas si l'objet n'existe pas? 🙂
Logique de la raison
Vous utilisez le mot clé virtual lorsque vous souhaitez déclarer un peu polymorphes comportement. Mais il n'y a rien polymorphes avec des constructeurs , constructeurs de travail en C++ est de simplement mettre un objet de données sur la mémoire . Depuis des tables virtuelles (et le polymorphisme en général) sont tous sur polymorphes comportement plutôt sur polymorphe de données , Il est inutile de déclarer un constructeur virtuel.
Nous faisons, c'est juste pas un constructeur 🙂
Des raisons sémantiques de côté, il n'y a pas de vtable jusqu'à ce que après que l'objet est construit, et de faire ainsi un virtuel désignation inutile.
typeid(*this).name()
.Résumé: la Norme C++ pourrait spécifier une notation et le comportement de "virtuel constructeur"s qui est assez intuitif et pas trop dur pour les compilateurs de soutien, mais pourquoi faire un changement de Norme pour cette notamment lorsque la fonctionnalité peut déjà être correctement mis en œuvre à l'aide de
create()
/clone()
(voir ci-dessous)? Il n'est pas aussi utile que de nombreuses autres langues proposition dans le pipeline.Discussion
Laissez le postulat d'un "virtuel constructeur" mécanisme:
Ci-dessus, la première ligne construit un
Derived
objet, de sorte*p
virtuelle expédition table peut raisonnablement fournir un "virtuel constructeur" pour une utilisation dans la deuxième ligne. (Des dizaines de réponses sur cette page indiquant "l'objet n'existe pas encore de manière virtuelle la construction est impossible" sont inutilement myope porté sur l'objet construit.)La deuxième ligne postulats de la notation
new p->Base()
à la demande de l'allocation dynamique et par défaut de la construction d'un autreDerived
objet.Notes:
le compilateur doit orchestrer l'allocation de la mémoire avant d'appeler le constructeur - constructeurs normalement soutien automatique (officieusement "pile") allocation, statique (pour global/espace de noms de la portée et de la classe/fonction-
static
objets), et dynamique (officieusement "tas") lorsquenew
est utiliséla taille de l'objet à être construit par
p->Base()
peut généralement pas être connue à la compilation, donc l'allocation dynamique est la seule approche qui fait sensalloca()
- mais conduit à d'importantes inefficacités et de la complexité (par exemple, ici et ici respectivement)pour l'allocation dynamique, il doit retourner un pointeur ainsi, la mémoire peut être
delete
d plus tard.la postulé notation explicitement listes
new
d'insister sur l'allocation dynamique et le pointeur type de résultat.Le compilateur devra:
Derived
nécessaire, soit par l'appel implicitevirtual
sizeof
fonction ou d'avoir de telles informations disponibles via le RTTIoperator new(size_t)
d'allouer de la mémoireDerived()
avec le placementnew
.OU
Soi - il ne semble pas insurmontable pour spécifier et mettre en œuvre des constructeurs virtuels, mais le million dollar question est: comment serait-il mieux que ce qui est possible à l'aide de C++ existant fonctionnalités de la langue...? Personnellement, je ne vois pas l'avantage, par rapport à la solution ci-dessous.
"clone ()" et " create()`
La C++ FAQ documents "virtuel constructeur" l'idiome, contenant
virtual
create()
etclone()
méthodes à défaut de construire ou copiez-la construction d'un nouveau allouée dynamiquement l'objet:Il est également possible de modifier ou de surcharge
create()
à accepter des arguments, mais pour correspondre à la classe de base /interfacevirtual
signature de fonction, les arguments pour les remplacements doivent correspondre exactement à celui de la classe de base des surcharges. Avec ces explicite de l'utilisateur des installations, il est facile d'ajouter de journalisation, d'instrumentation, de modifier l'allocation de la mémoire etc..clone
etcreate
fonctions ne fonctionnent pas avec les conteneurs, ne fonctionnent pas avec le passage par valeur, et cætera. Afin de ne pas obtenir ce que nous voulons -- polymorphisme sans découpage tout en préservant la valeur ordinaire de la sémantique.create
ne pas travailler directement avec les conteneurs Standard, mais il est trivial d'écrire un petit type de gestion queclone
s à partir du constructeur de copie etc (voir, par exemple, ici). Ces objets de gestion peuvent également être passés par valeur si vous trouvez que plus facile que d'utiliser des références. Avecclone
/create
private
et la gestion de l'objet-friend
-ed, vous pouvez vous assurer de la cohérence de l'utilisation. Pourtant, c'est vrai que c'est une couche supplémentaire de complexité qui peut frustrer les plus récents, les programmeurs en C++....operator<
. Aussi, puisqu'il ne fait pas partie de la langue, il sera très difficile de faire un code qui utilise une telle chose interagir avec du code qui ne fonctionne pas.Vous pouvez trouver un exemple et la raison technique pour laquelle il n'est pas permis à stefan @'s réponse. Maintenant, une réponse logique à cette question selon moi est:
Le principal usage du mot clé virtual est de permettre polymorphes comportement quand nous ne savons pas quel est le type de l'objet de la classe de base pointeur pointera à.
Mais pense que cela est plus primitive, pour l'utilisation de virtual fonctionnalité vous aurez besoin d'un pointeur. Et ce n'est un pointeur besoin? Un objet à point de! (en considérant le cas pour l'exécution correcte du programme)
Donc, nous avons essentiellement besoin d'un objet qui existe déjà quelque part dans la mémoire (nous ne sommes pas intéressés à la façon dont la mémoire a été allouée, il est peut-être au moment de la compilation ou à l'exécution), de sorte que notre pointeur peut pointer correctement à cet objet.
Maintenant, de penser à la situation sur le moment lorsque l'objet de la classe pour être souligné est affecté de la mémoire -> Son constructeur sera appelé automatiquement lors de l'instance en elle-même!
On peut donc constater que nous n'avons pas besoin de vous soucier de l'constructeur virtuelle, parce que dans tout les cas, vous souhaitez utiliser un comportement polymorphe notre constructeur aurait déjà été exécuté faire de notre objet prêt à être utilisé!
Bien que le concept de virtuel les constructeurs ne cadrent pas bien depuis type d'objet est pré-requis pour la création d'objet, il n'est pas complètement ignoré.
GOF de l'usine de la méthode "design pattern permet d'utiliser le "concept" de virtuel constructeur, ce qui est pratique dans certaines situations de calcul.
Fonctions virtuelles en C++ sont une mise en application du polymorphisme de l'exécution, et ils feront de la fonction prépondérante. Généralement le
virtual
mot-clé est utilisé en C++ quand vous avez besoin le comportement dynamique. Il ne fonctionne que lorsque l'objet existe. Alors que les constructeurs sont utilisés pour créer des objets. Constructeurs sera appelée au moment de la création de l'objet.Donc, si vous créez le constructeur comme
virtual
, comme par le mot clé virtual définition, il doit avoir un objet existant à utiliser, mais le constructeur est utilisé pour créer l'objet, de sorte que ce cas n'existe pas. Donc, vous ne devriez pas utiliser le constructeur virtuel.Donc, si nous essayons de nous déclarer virtuelle constructeur compilateur renvoie une Erreur:
Quand les gens posent une question comme ça, j'aime à penser à moi-même "qu'arriverait-il si c'était réellement possible?" Je ne sais pas vraiment ce que cela signifie, mais je pense qu'il aurait quelque chose à voir avec le fait d'être en mesure de remplacer le constructeur mise en œuvre, basé sur le type dynamique de l'objet créé.
Je vois un certain nombre de problèmes potentiels avec cette. Pour une chose, la classe dérivée ne sera pas entièrement construite à l'époque du virtuel constructeur est appelé, il y a donc des problèmes potentiels avec la mise en œuvre.
Deuxièmement, ce qui se passerait dans le cas de l'héritage multiple? Votre constructeur virtuel serait appelé plusieurs fois probablement, vous devez avoir un moyen de savoir qui a appelé.
Troisièmement, en général au moment de la construction, l'objet n'a pas la table virtuelle entièrement construit, ce qui signifie qu'il aurait besoin d'un grand changement de la spécification du langage pour permettre le fait que le type dynamique de l'objet qui allait être connu au moment de la construction. Cela permettrait alors de la base de constructeur de classe peut-être appeler d'autres fonctions virtuelles au moment de la construction, avec un pas entièrement construite dynamique type de classe.
Enfin, comme quelqu'un l'a souligné, vous pouvez mettre en œuvre une sorte de virtual constructeur statique à l'aide de "créer" ou "init" type de fonctions qui, en gros, faire la même chose qu'un constructeur virtuel ferait.
Fonctions virtuelles sont utilisées pour invoquer les fonctions sont basées sur le type de l'objet pointé par le pointeur, et non le type de pointeur lui-même. Mais un constructeur n'est pas "invoquée". Il est appelé qu'une seule fois lorsqu'un objet est déclaré. Ainsi, un constructeur ne peut pas être virtuelles en C++.
Vous ne devez pas appeler une fonction virtuelle au sein de votre constructeur soit. Voir : http://www.artima.com/cppsource/nevercall.html
En plus je ne suis pas sûr que vous avez vraiment besoin d'un constructeur virtuel. Vous pouvez obtenir des polymorphes de la construction sans elle: vous pouvez écrire une fonction qui permettra de construire votre objet, selon les paramètres nécessaires.
Virtuelle-table(vtable) est effectué pour chaque Classe ayant un ou plus "virtuelle-fonctions'. Chaque fois qu'un Objet est créé de telle classe, il contient une "virtuel de pointeur' qui pointe vers la base correspondant à la vtable. Chaque fois qu'il y a un appel de fonction virtuelle, la vtable est utilisé pour résoudre l'adresse de fonction.
Le constructeur ne peut pas être virtuel, parce que quand un constructeur d'une classe est exécuté, il n'y a pas de vtable dans la mémoire, signifie pas de virtuel pointeur encore définie. D'où le constructeur doit toujours être non-virtuel.
Cant nous disons tout simplement qu'il aime.. On ne peut pas hériter des constructeurs. Donc, il n'y a pas de point déclarant virtuel car le virtuel fournit polymorphisme .
Le virtuel mécanisme ne fonctionne que lorsque vous avez une classe en fonction de pointeur vers un objet de classe dérivée. La Construction a ses propres règles concernant l'appel de la classe de base des constructeurs, essentiellement de la classe de base de dérivés. Comment un constructeur virtuel est utile ou appelé? Je ne sais pas quelles autres langues, mais je ne vois pas comment un constructeur virtuel pourrait être utile ou même mis en place. La Construction doit avoir eu lieu pour le virtuel mécanisme pour donner un sens et de la construction doit également avoir eu lieu pour la vtable de structures ont été créées, qui fournit la mécanique du comportement polymorphe.
Il y a une très simple raison: les Constructeurs sont effectivement des fonctions statiques, et en C++ aucune fonction statique peut être virtuel.
Si vous avez beaucoup d'expérience avec C++, vous savez tout sur la différence entre statique & fonctions de membre. Les fonctions statiques sont associés à la CLASSE, et non pas les objets (instances), de sorte qu'ils ne voient pas d'un pointeur "this". Seulement des fonctions de membre peut être virtuel, parce que la vtable - le caché tableau de pointeurs de fonction qui fait "virtuel" de travail est vraiment un membre de données de chaque objet.
Maintenant, qu'est-ce que le constructeur de l'emploi? C'est dans le nom - un "T" constructeur initialise T les objets comme ils sont affectés. Automatiquement, cela s'oppose à une fonction de membre de! Un objet doit EXISTER avant d'avoir un pointeur "this" et donc une vtable. Cela signifie que même si la langue traitée constructeurs comme des fonctions (il n'a pas, pour des raisons que je ne vais pas entrer dans), ils doivent être des fonctions de membre statique.
Une excellente façon de voir cela est de regarder la "Fabrique" de modèle, en particulier de l'usine de fonctions. Ils font ce que vous êtes après, et vous remarquerez que si la classe T est une méthode de fabrique, il est TOUJOURS STATIQUE. Il doit être.
A f (g);
appelle un constructeur de copie. Et il y a un objet qui pourrait être une fonction membre de,g
. Ouvoid foo (A a); ... foo(f);
. Ici, nous avons besoin de construire une nouvelleA
appelerfoo
, et regarde, il y a un objet qui pourrait être une fonction membre de --f
.C++ virtuel constructeur n'est pas possible.Par exemple, vous ne pouvez pas marquer un constructeur virtuel.Essayez ce code
Il provoque une erreur.Ce code est d'essayer de déclarer un constructeur virtuel.
Maintenant, laissez-nous essayer de comprendre pourquoi nous utilisons le mot clé virtual. Mot-clé virtuel est utilisé pour fournir au moment de l'exécution du polymorphisme. Par exemple, essayez ce code.
Dans les principales
a=new anotherClass;
alloue de la mémoire pouranotherClass
dans un pointeura
déclaré comme type deaClass
.Cela provoque à la fois le constructeur (DansaClass
etanotherClass
) pour appeler automatiquement.Donc, nous n'avons pas besoin de marque constructeur virtuel.Parce que quand un objet est créé, il doit suivre la chaîne de création (j'.e première base, puis les classes dérivées).Mais quand nous essayons de supprimer un
delete a;
il provoque à appeler uniquement la base destructeur.Donc, nous avons à gérer le destructeur virtuel à l'aide de mots clés. Virtuelles constructeur n'est pas possible, mais destructeur virtuel est.GrâceSi vous pensez logiquement comment les constructeurs de travail et le sens/l'utilisation d'une fonction virtuelle est en C++, alors vous réaliserez qu'un constructeur virtuel serait dénuée de sens en C++. Déclarer quelque chose de virtuel en C++ signifie qu'il peut être remplacée par une sous-classe de la classe actuelle, cependant, le constructeur est appelé lorsque l'opposé est créé, à l'époque, vous ne pouvez pas créer une sous-classe de la classe, vous devez être la création de la classe donc il n'y en aurait jamais besoin de déclarer un constructeur virtuel.
Et une autre raison est que les constructeurs ont le même nom que son nom de la classe et, si nous déclarons constructeur virtuel, alors il devrait être redéfini dans sa classe dérivée avec le même nom, mais vous ne pouvez pas avoir le même nom de deux classes. Donc, il n'est pas possible d'avoir un constructeur virtuel.
Quand un constructeur est appelé, bien qu'il n'y a pas d'objet créé jusqu'à ce point, nous en savons encore le genre d'objet qui va être créé car le spécifique constructeur de la classe à laquelle l'objet appartient a déjà été appelée.
Virtual
mot clé associé à une fonction signifie la fonction d'un type d'objet particulier va être appelé.Donc, ma réflexion a dit qu'il n'est pas nécessaire de faire le virtuel constructeur, parce que déjà souhaité constructeur dont l'objet va être créé a été invoquée et faire de constructeur virtuel est juste redondant chose à faire, car l' objet spécifique constructeur a déjà été invoqué et c'est la même que l'appel à la spécifiques à la classe de fonction qui est atteint par le mot clé virtual.
Bien que l'intérieur de la mise en œuvre ne permet pas de virtuel constructeur de vptr et vtable des raisons.
Une autre raison est que le C++ est un langage statiquement typé et nous avons besoin de connaître le type d'une variable au moment de la compilation.
Le compilateur doit être conscient du type de classe pour créer l'objet. Le type d'objet à créer est une compilation de décision.
Si nous faisons le constructeur virtuel, alors cela signifie que nous n'avons pas besoin de connaître le type de l'objet au moment de la compilation(c'est ce que la fonction virtuelle fournir. Nous n'avons pas besoin de connaître l'objet réel et juste besoin de la base de pointeur d'un objet réel appel de l'objet pointé fonctions virtuelles sans connaître le type de l'objet) et si nous ne connaissons pas le type de l'objet au moment de la compilation, alors il est contre les langages à typage statique. Et donc, polymorphisme de l'exécution ne peut pas être atteint.
Par conséquent, le Constructeur ne sera pas appelé sans connaître le type de l'objet au moment de la compilation. Et donc l'idée de faire un virtuel constructeur échoue.
La Vpointer est créé au moment de la création de l'objet. vpointer coutume existe avant la création de l'objet. donc, il n'y a pas de point d'en faire le constructeur virtuel.