En C++, il n'existe pas de notion de 'constructeur virtuel' au sens strict, cependant, la nécessité de créer des instances d'objets de classes dérivées avec un type connu uniquement au moment de l'exécution se présente souvent. Historiquement, un analogue à cette tâche est résolu par le modèle "constructeur virtuel" via des fonctions virtuelles — généralement "clone()" ou "create()".
Historique de la question: En C++, depuis ses premières versions, il y a eu une limitation : un constructeur ne peut pas être déclaré comme virtuel. Cela dit, parfois, dans les hiérarchies de classes, il est nécessaire de créer de nouveaux objets à partir d'un existant (ou de connaître le type uniquement au moment de l'exécution).
Problème : Classiquement, les constructeurs ne respectent aucun mécanisme de fonctions virtuelles — l'appel est toujours résolu au moment de la compilation. Cela ne permet pas d'obtenir une "usine vivante" pour générer des objets avec leur véritable type d'exécution via le constructeur de la classe de base.
Solution : Il est recommandé de réaliser une fonction virtuelle dans la classe de base — généralement cela serait clone() (créer une copie de l'objet) ou create() (créer un objet du même type sans copier l'état).
Exemple de code :
class Base { public: virtual ~Base() {} virtual Base* clone() const = 0; }; class Derived : public Base { public: Derived(int v) : value(v) {} Base* clone() const override { return new Derived(*this); } private: int value; }; void process(const Base& b) { Base* b2 = b.clone(); // Créons la bonne copie via la méthode virtuelle delete b2; }
Caractéristiques clés :
Les constructeurs peuvent-ils être déclarés virtual en C++ ?
Non, la syntaxe C++ ne permet pas le spécificateur virtual pour le constructeur. Dans le cas contraire, le compilateur générera une erreur de compilation.
Si l'on déclare clone() soi-même, est-il obligatoire de le faire virtuel pur dans la classe de base ?
Non, ce n'est pas obligatoire. On peut donner une implémentation par défaut à clone(), par exemple, s'il est utile de copier seulement une partie de l'état ou de retourner nullptr, mais il est généralement fait en tant que fonction virtuel pure pour un meilleur contrôle.
Peut-on utiliser des méthodes statiques d'usine en remplacement de clone() ? Comment cela se rapporte-t-il à la virtualité ?
Les méthodes statiques d'usine ne sont pas virtuelles et ne sont pas redéfinies dans les dérivés par le mécanisme classique. Pour un véritable "constructeur virtuel", une fonction virtuelle d'instance est nécessaire ou un autre moyen de résolution dynamique de type.
Un développeur a implémenté le modèle via une méthode statique :
class Base { public: static Base* create() { return new Base; } }; class Derived : public Base {}; // ... appelle Base::create(), retourne Base, perte d'information sur le type réel
Avantages :
Inconvénients :
Le code utilise clone() :
class Base { public: virtual ~Base() {} virtual Base* clone() const = 0; }; class Derived : public Base { int x; public: Derived(int x) : x(x) {} Base* clone() const override { return new Derived(*this); } };
Avantages :
Inconvénients :