Constructeur appelant constructeur : chaînes en C++ — est-ce possible ?

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

« D'un constructeur à un autre » : la question éternelle du développeur C++

\n\n

Imaginez la situation : vous écrivez une classe avec plusieurs constructeurs. L'un prend trois paramètres, un autre deux, un troisième un seul. Et dans tous, la même logique d'initialisation se répète. Vous avez envie d'écrire quelque chose comme MyClass() : MyClass(42, "default") {} — et d'oublier la duplication. Mais le compilateur C++ (jusqu'à un certain point) regarde cela de travers. Peut-on vraiment appeler un constructeur depuis un autre constructeur ? Et si oui — comment ?

\n\n

Cette question est l'une des plus populaires sur Stack Overflow (des dizaines de milliers de vues). Sans surprise : le sujet des chaînes de constructeurs (constructor chaining) est un véritable obstacle pour les débutants et même les développeurs expérimentés qui passent au C++ depuis Java ou Python. Dans cet article, nous allons analyser trois approches pour résoudre le problème, des « béquilles » aux solutions élégantes de C++11, et déterminer laquelle utiliser dans du code réel.

\n\n

Pourquoi ne peut-on pas simplement appeler un constructeur depuis un constructeur ?

\n\n

L'approche naïve ressemble à ceci :

\n\n
class MyClass {\npublic:\n    MyClass() {\n        // du code\n    }\n    MyClass(int x) {\n        MyClass(); // ERREUR : ce n'est pas possible !\n    }\n};
\n\n

En C++, un constructeur n'est pas une fonction ordinaire. Il initialise l'objet une seule fois. Si vous essayez d'appeler explicitement un autre constructeur dans le corps, le compilateur interprétera cela comme la création d'un objet temporaire — et rien ne sera initialisé dans l'instance actuelle. Résultat : soit une erreur de compilation, soit (pire) un comportement indéfini.

\n\n

Avant la norme C++11, la seule manière légale de « partager » la logique d'initialisation était d'appeler une méthode privée init(). Mais ce n'était pas une véritable délégation : les membres de la classe étaient d'abord initialisés par le constructeur par défaut, puis réécrits. Inefficace et source de bugs.

\n\n

Approche n°1 : constructeurs délégants (C++11 et plus récent)

\n\n

À partir de C++11, le langage a introduit une fonctionnalité tant attendue — les constructeurs délégants (delegating constructors). Il est désormais possible d'appeler un constructeur depuis un autre directement dans la liste d'initialisation :

\n\n
class MyClass {\n    int value;\n    std::string name;\npublic:\n    // Constructeur de base\n    MyClass(int v, const std::string& n) : value(v), name(n) {\n        std::cout << "Initialisation complète : " << value << ", " << name << "\\n";\n    }\n    // Constructeur délégant\n    MyClass(int v) : MyClass(v, "default") {}\n    // Un autre constructeur délégant\n    MyClass() : MyClass(0, "default") {}\n};
\n\n

Comment cela fonctionne-t-il ? Le constructeur MyClass(int v) transmet le contrôle au constructeur MyClass(int, string). Celui-ci effectue toute l'initialisation, et ce n'est qu'ensuite que le contrôle revient. Règle importante : dans la liste d'initialisation, il est interdit de mélanger l'appel d'un autre constructeur avec l'initialisation directe des membres. Soit la délégation, soit sa propre initialisation — l'un ou l'autre.

\n\n

Avantages et inconvénients

\n
    \n
  • ✅ Élégance : le code devient propre, sans duplication.
  • \n
  • ✅ Performance : l'objet est initialisé une seule fois, sans opérations superflues.
  • \n
  • ⚠️ Limitation : la délégation ne fonctionne que sur un seul « niveau » — la chaîne ne peut pas être récursive (vous provoqueriez un débordement de pile).
  • \n
  • ⚠️ Compatibilité : nécessite C++11 ou plus récent. Si vous êtes bloqué sur un ancien compilateur — cette option n'est pas pour vous.
  • \n
\n\n

Approche n°2 : méthode privée init()

\n\n

La méthode classique « pré-C++11 » consiste à extraire la logique commune dans une méthode privée. Cela ressemble à ceci :

\n\n
class MyClass {\n    int value;\n    std::string name;\n    void init(int v, const std::string& n) {\n        value = v;\n        name = n;\n        std::cout << "Init appelé\\n";\n                

Blogs

Book Recommendations