Pourquoi n'avons-nous pas un constructeur virtuel en C++?

pourquoi C++ n'a-t-il pas de constructeur virtuel?

204
demandé sur nitin_cherian 2009-04-09 12:46:31

20 réponses

l'Entendre de la bouche des chevaux:).

D'après la FAQ de Bjarne Stroustrup sur le Style et la Technique C++ pourquoi n'avons-nous pas de constructeurs virtuels?

Un appel virtuel est un mécanisme pour obtenir le travail effectué partiels information. En particulier, "virtuel" nous permet d'appeler une fonction ne connaissant que les interfaces et non le type exact de l'objet. De créer un objet vous avez besoin d'informations complètes. Dans en particulier, vous besoin de connaître le type exact de ce que vous voulez créer. Conséquent, un "appel à un constructeur" ne peut pas être virtuel.

l'entrée FAQ continue pour donner le code pour un moyen d'atteindre cet objectif sans un constructeur virtuel.

203
répondu aJ. 2015-02-13 10:53:27

les fonctions virtuelles fournissent essentiellement un comportement polymorphe. C'est-à-dire que lorsque vous travaillez avec un objet dont le type dynamique est différent du type statique (temps de compilation) auquel il est fait référence, il fournit un comportement qui est approprié pour le type actuel d'objet au lieu du 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 la même que le type d'objet réel depuis:

pour construire un objet, un constructeur a besoin du type exact de l'objet qu'il doit créer [...] Outre.[ ..]vous ne pouvez pas avoir un pointeur vers un constructeur

(Bjarne Stroustup (P424 Le Langage de Programmation C++ SE))

118
répondu Anton Gogolev 2009-04-09 08:51:52

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 abstract factory pattern , car vous pouvez passer l'objet représentant la classe autour au lieu de faire votre propre), C++ est un langage basé sur la classe, et n'a pas d'objets représentant l'une des constructions du langage. La classe n'existe pas en tant qu'objet à l'exécution, donc vous ne pouvez pas appel d'une méthode virtuelle.

cela correspond à la philosophie "vous ne payez pas pour ce que vous n'utilisez pas", bien que chaque grand projet C++ que j'ai vu ait fini par mettre en œuvre une forme d'usine abstraite ou de réflexion.

56
répondu Pete Kirkham 2009-04-09 09:08:19

deux raisons auxquelles je peux penser:

raison technique

l'objet n'existe qu'après la fin du constructeur.Pour que le constructeur soit envoyé en utilisant la table virtuelle , il doit y avoir un objet existant avec un pointeur vers la table virtuelle, mais comment un pointeur vers la table virtuelle peut-il exister si l'objet n'existe toujours pas? :)

logique raison

vous utilisez le mot-clé virtuel lorsque vous souhaitez déclarer un peu polymorphes comportement. Mais il n'y a rien de polymorphe avec les constructeurs , le travail des constructeurs en C++ est simplement de mettre des données objet sur la mémoire . Étant donné que les tables virtuelles (et le polymorphisme en général) portent toutes sur le comportement polymorphe plutôt que sur les données polymorphiques , il n'y a aucun sens à déclarer un constructeur virtuel.

35
répondu user88637 2009-04-09 21:20:26

Nous faisons, c'est juste pas un constructeur :-)

struct A {
  virtual ~A() {}
  virtual A * Clone() { return new A; }
};

struct B : public A {
  virtual A * Clone() { return new B; }
};

int main() {

   A * a1 = new B;
   A * a2 = a1->Clone();    // virtual construction
   delete a2;
   delete a1;
}
11
répondu 2009-04-09 08:51:07

pour des raisons sémantiques mises à part, il n'y a pas de vtable avant la construction de l'objet, ce qui rend une désignation virtuelle inutile.

11
répondu Marius 2009-11-23 17:26:58

résumé : la norme C++ pourrait spécifier une notation et un comportement pour "le constructeur virtuel"s qui est raisonnablement intuitif et pas trop difficile à prendre en charge par les compilateurs, mais pourquoi faire un changement de norme pour cela spécifiquement lorsque la fonctionnalité peut déjà être proprement mis en œuvre en utilisant create() / clone() (voir ci-dessous)? Ce n'est pas aussi utile que beaucoup d'autres proposition linguistique en préparation.

Discussion

postulons un mécanisme de "constructeur virtuel":

Base* p = new Derived(...);
Base* p2 = new p->Base();  // possible syntax???

ci-dessus, la première ligne construit un Derived objet *p virtuelle expédition table peut raisonnablement fournir un "virtuel constructeur" pour une utilisation dans la deuxième ligne. (Des douzaines de réponses sur cette page indiquant "l'objet n'existe pas encore donc la construction virtuelle est impossible " sont inutilement myopiquement axés sur l'objet à construire.)

la deuxième ligne postule la notation new p->Base() pour demander l'attribution dynamique et la construction par défaut d'un autre objet Derived .

Notes:

  • le compilateur doit orchestrer l'allocation de mémoire avant d'appeler le constructeur - les constructeurs supportent normalement l'allocation automatique (officieusement" stack"), statique (pour la portée globale / namespace et la classe - / fonction - static objets), et dynamique (informellement" heap") lorsque new est utilisé

    • la taille de l'objet à construire par p->Base() ne peut généralement pas être connue au moment de la compilation, donc allocation dynamique est la seule approche qui a du sens

  • pour l'allocation dynamique il doit retourner un pointeur pour que la mémoire puisse être delete d plus tard.

  • la notation postulée mentionne explicitement new pour mettre l'accent sur l'allocation dynamique et le type de résultat du pointeur.

le compilateur devrait:

  • découvrez combien de mémoire Derived nécessaire, soit par appeler une fonction implicite virtual sizeof ou avoir de telles informations disponibles via RTTI
  • appel operator new(size_t) pour allouer de la mémoire
  • invoquer Derived() placement new .

OU

  • créer une entrée vtable supplémentaire pour une fonction qui combine l'allocation dynamique et la construction

il ne semble pas insurmontable pour spécifier et implémenter des constructeurs virtuels, mais la question à un million de dollars est: comment serait-ce mieux que ce qui est possible en utilisant les fonctionnalités C++ existantes...? Personnellement, Je ne vois aucun avantage sur la solution ci-dessous.


`clone () `et` create () '

Le C++ FAQ documents "virtuel constructeur" idiome , contenant virtual create() et clone() méthodes par défaut-construire ou copier-construire un nouvel objet attribué dynamiquement:

class Shape {
  public:
    virtual ~Shape() { } // A virtual destructor
    virtual void draw() = 0; // A pure virtual function
    virtual void move() = 0;
    // ...
    virtual Shape* clone() const = 0; // Uses the copy constructor
    virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
  public:
    Circle* clone() const; // Covariant Return Types; see below
    Circle* create() const; // Covariant Return Types; see below
    // ...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }

il est également possible de modifier ou de surcharger create() pour accepter des arguments, bien que pour correspondre à la signature de la fonction virtual de la classe de base / interface, les arguments pour outrepasser doivent correspondre exactement à l'une des surcharges de la classe de base. Avec ces installations explicitement fournies par l'utilisateur, il est facile d'ajouter la journalisation, instrumentation, modification de l'attribution de la mémoire, etc..

9
répondu Tony Delroy 2017-05-23 10:31:17

bien que le concept de constructeur virtuel ne Cadre pas bien puisque le type d'objet est une condition préalable à la création d'un objet, il n'est pas complètement dépassé.

le modèle de conception de la "méthode d'usine" de GOF utilise le "concept" de constructeur virtuel, qui est manuel dans certaines situations de conception.

4
répondu Shraddha Sinha 2011-10-17 09:43:14

les fonctions virtuelles sont utilisées pour invoquer des fonctions basées sur le type d'objet pointé par le pointeur, et non sur 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 rendu virtuel en C++.

3
répondu skrtbhtngr 2013-11-27 14:45:34

fonctions Virtuelles en C++ sont une mise en application du polymorphisme de l'exécution, et ils feront de la fonction prépondérante. En général, le mot-clé virtual est utilisé en C++ lorsque vous avez besoin de 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 , selon la définition de mot-clé virtuel, il devrait avoir 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 déclarer le compilateur de constructeur virtuel jeter une erreur:

les constructeurs ne peuvent pas être déclarés virtuels

3
répondu Neha kumari 2015-07-21 18:25:53

vous pouvez trouver un exemple et la raison technique pour laquelle il n'est pas permis dans la réponse de @stefan. Maintenant, une réponse logique à cette question selon moi est:

l'utilisation principale du mot-clé virtuel est de permettre un comportement polymorphe lorsque nous ne savons pas quel type d'objet le pointeur de classe de base pointera.

mais pensez à ceci est une façon plus primitive, pour l'utilisation de la fonctionnalité virtuelle, vous aurez besoin d'un pointeur. Et ce n'est un pointeur exiger? Un objet à point de! (en considérant le cas pour l'exécution correcte du programme)

ainsi, nous avons essentiellement besoin d'un objet qui existe déjà quelque part dans la mémoire (nous ne sommes pas concernés par la façon dont la mémoire a été attribuée, il peut être au moment de la compilation ou de l'exécution) de sorte que notre pointeur puisse correctement pointer vers cet objet.

maintenant, pensez à la situation du moment où l'objet de la classe à pointer est assigné à un certain souvenir -> Son constructeur sera appelé automatiquement à cette instance!

donc nous pouvons voir que nous n'avons pas réellement besoin de nous inquiéter du fait que le constructeur soit virtuel, parce que dans tous les cas vous souhaitez utiliser un comportement polymorphe notre constructeur aurait déjà été exécuté rendant notre objet prêt pour l'utilisation!

3
répondu Kushan Mehta 2018-05-04 07:34:06

vous ne devriez pas appeler la fonction virtuelle dans votre constructeur non plus. Voir: http://www.artima.com/cppsource/nevercall.html

de plus, Je ne suis pas sûr que vous ayez vraiment besoin d'un constructeur virtuel. Vous pouvez réaliser une construction polymorphe sans elle: vous pouvez écrire une fonction qui construira votre objet selon les paramètres nécessaires.

2
répondu Edouard A. 2009-04-09 08:51:05

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 signifierait, mais je suppose que cela aurait quelque chose à voir avec le fait de pouvoir outrepasser l'implémentation du constructeur basée sur le type dynamique de l'objet créé.

je vois un certain nombre de problèmes potentiels avec cette. D'une part, la classe dérivée ne sera pas entièrement construite au moment où le virtuel le constructeur est appelé, donc il y a des problèmes potentiels avec la mise en œuvre.

deuxièmement, que se passerait-il en cas d'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, cela signifie qu'il faut une grande modification de la spécification linguistique pour tenir compte du fait que le type dynamique de l'objet serait connu au moment de la construction. Cela permettrait alors au constructeur de classe de base d'appeler peut-être d'autres fonctions virtuelles au moment de la construction, avec un type de classe dynamique pas entièrement construit.

enfin, comme quelqu'un d'autre l'a souligné, vous pouvez implémenter une sorte de constructeur virtuel en utilisant des fonctions statiques de type "create" ou "init" qui font essentiellement la même chose qu'un virtuel constructeur ferait.

2
répondu 1800 INFORMATION 2009-04-09 08:57:10

le mécanisme virtuel ne fonctionne que lorsque vous avez un pointeur de classe basé sur un objet de classe dérivé. Construction a ses propres règles pour l'appel des constructeurs de classe de base, essentiellement de classe de base à dérivé. Comment un constructeur virtuel est utile ou appelé? Je ne sais pas ce que font les autres langues, mais je ne vois pas comment un constructeur virtuel pourrait être utile ou même implémenté. La Construction doit avoir eu lieu pour que le mécanisme virtuel ait un sens et la construction aussi il faut que les structures vtable aient été créées pour fournir la mécanique du comportement polymorphe.

1
répondu Rich 2010-04-14 18:33:10

on ne peut pas simplement le dire comme ça.. Nous ne pouvons pas hériter des constructeurs. Il est donc inutile de les déclarer virtuels, car le virtuel offre du polymorphisme .

1
répondu user3004790 2013-11-18 13:06:25

une table virtuelle(vtable) est créée pour chaque classe ayant une ou plusieurs "fonctions virtuelles". Chaque fois qu'un objet est créé d'une telle classe, il contient un "pointeur virtuel" qui pointe vers la base du vtable correspondant. Chaque fois qu'il y a un appel de fonction virtuel, le vtable est utilisé pour résoudre à l'adresse de fonction. Le constructeur ne peut pas être virtuel, parce que lorsque le constructeur d'une classe est exécuté il n'y a pas de vtable dans la mémoire, ce qui signifie qu'aucun pointeur virtuel n'est encore défini. D'où l' le constructeur doit toujours être non-virtuel.

1
répondu Navneet Agarwal 2016-09-21 17:34:42

virtuelle C++ constructeur n'est pas possible.Par exemple, vous ne pouvez pas marquer un constructeur virtuel.Essayez ce code

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        virtual aClass()
        {   
        }  
};
int main()
{
    aClass a; 
}

Il provoque une erreur.Ce code essaie de déclarer un constructeur comme virtuel. Essayons maintenant de comprendre pourquoi nous utilisons le mot-clé virtuel. Le mot-clé virtuel est utilisé pour fournir le polymorphisme du temps d'exécution. Par exemple, essayez ce code.

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        aClass()
        {
            cout<<"aClass contructor\n";
        }
        ~aClass()
        {
            cout<<"aClass destructor\n";
        }

};
class anotherClass:public aClass
{

    public:
        anotherClass()
        {
            cout<<"anotherClass Constructor\n";
        }
        ~anotherClass()
        {
            cout<<"anotherClass destructor\n";
        }

};
int main()
{
    aClass* a;
    a=new anotherClass;
    delete a;   
    getchar(); 
}

En main a=new anotherClass; alloue de la mémoire pour les anotherClass dans un pointeur a déclaré comme type de aClass .Cela fait que le constructeur (dans aClass et anotherClass ) appelle automatiquement.Nous n'avons donc pas besoin de marquer le constructeur comme étant virtuel.Parce que lorsqu'un objet est créé, il doit suivre la chaîne de création (I. e d'abord la base et ensuite les classes dérivées). Mais quand nous essayons de supprimer un delete a; il provoque à appeler seulement le destructeur de base.Donc nous devons gérer le destructeur en utilisant le mot-clé virtuel. donc le constructeur virtuel n'est pas possible mais destructeur virtuel est .Merci

0
répondu Tunvir Rahman Tusher 2013-06-23 11:47:36

il y a une raison très simple: les constructeurs sont effectivement des fonctions statiques, et en C++ Aucune fonction statique ne peut être virtuelle.

si vous avez beaucoup d'expérience avec C++, vous savez tout sur la différence entre les fonctions statiques et les fonctions de membre. Les fonctions statiques sont associées à la classe, pas aux objets (instances), donc ils ne voient pas de pointeur "ceci". Seules les fonctions de membre peuvent être virtuelles, parce que le vtable-la table cachée de pointeurs de fonction qui fait "virtuel" de travail est vraiment un membre de données de chaque objet.

maintenant, quel est le travail du constructeur? Il est dans le nom-un constructeur" T " initialise les objets T au fur et à mesure qu'ils sont alloués. Cela empêche automatiquement qu'il soit une fonction de membre! Un objet doit exister avant d'avoir un pointeur "ceci" et donc un vtable. Cela signifie que même si le langage traitait les constructeurs comme des fonctions ordinaires (ce n'est pas le cas, pour des raisons connexes que je n'entrerai pas), ils devraient être membres statiques. fonction.

une bonne façon de voir cela est de regarder le modèle" usine", en particulier les fonctions d'usine. Ils font ce que vous voulez, et vous remarquerez que si la classe T a une méthode d'usine, elle est toujours statique. Il doit être.

0
répondu user3726672 2015-07-23 21:55:36

si vous pensez logiquement au fonctionnement des constructeurs et à la signification/utilisation d'une fonction virtuelle en C++, alors vous réaliserez qu'un constructeur virtuel serait dénué de sens en C++. Déclarer quelque chose de virtuel en C++ signifie qu'il peut être dépassé par une sous-classe de la classe courante, cependant le constructeur est appelé quand l'objecté est créé, à ce moment vous ne pouvez pas créer une sous-classe de la classe, vous devez créer la classe donc il ne serait jamais nécessaire de déclarer un constructeur virtuel.

et une autre raison est, les constructeurs ont le même nom que son nom de classe et si nous déclarons constructeur comme 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.

0
répondu shobhit2905 2017-12-11 14:15:15

le Vpointer est créé au moment de la création de l'objet. vpointer n'existe pas avant la création d'un objet. il n'y a donc pas de raison de rendre le constructeur virtuel.

-1
répondu ravi chandra 2015-09-24 01:54:29