ProgrammationDéveloppeur C++/Backend

Qu'est-ce que les constructeurs délégués en C++, quand et pourquoi les utiliser ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question

Avant la norme C++11, lorsqu'il était nécessaire d'écrire plusieurs constructeurs avec des paramètres différents, il fallait doubler le code d'initialisation dans chacun d'eux, car il n'était pas possible d'appeler un autre constructeur à l'intérieur des constructeurs de classe.

Problème

L'impossibilité d'utiliser déjà la logique d'initialisation existante dans d'autres constructeurs conduisait à une duplication de code et à des erreurs lors de la modification de la logique d'initialisation : en mettant à jour un constructeur, il était facile d'oublier les autres.

Solution

Avec la sortie de C++11, un mécanisme de "constructeurs délégués" a été introduit, permettant à un constructeur de classe d'appeler un autre constructeur de la même classe via la syntaxe de la liste d'initialisation.

Exemple de code :

class Widget { public: Widget() : Widget(0, "défaut") {} Widget(int n) : Widget(n, "utilisateur") {} Widget(int n, std::string name) : size(n), label(name) {} private: int size; std::string label; };

Maintenant, toute la logique commune est concentrée dans un "constructeur principal", tout le reste délègue l'appel.

Caractéristiques clés :

  • Permet d'éviter la duplication du code d'initialisation
  • Augmente la fiabilité et la maintenabilité
  • Délégation dans la liste d'initialisation, et non dans le corps du constructeur

Questions piégeuses.

Peut-on déléguer l'appel à un autre constructeur en appelant une fonction à l'intérieur du corps du constructeur ?

Non. L'appel d'un constructeur à partir d'un autre constructeur est possible uniquement via la liste d'initialisation, et non à l'intérieur du corps du constructeur. Si une fonction est appelée à partir du corps du constructeur, les membres de l'objet seront déjà initialisés.

Que se passe-t-il si nous créons un "cercle" de délégation entre les constructeurs ?

La délégation en boucle (par exemple, A délègue à B, et B à A) entraîne une erreur de compilation C++ : il ne peut pas y avoir de récursion infinie entre les constructeurs.

Peut-on déléguer l'appel au constructeur de la classe de base à l'aide d'un constructeur délégué de la classe dérivée ?

Non. Les constructeurs délégués fonctionnent uniquement dans une seule classe. Pour appeler le constructeur de base, une syntaxe séparée est utilisée :

class Base { public: Base(int) {} }; class Derived : public Base { public: Derived() : Base(42) {} };

Erreurs typiques et anti-modèles

  • Violation de la lisibilité avec un nombre excessif de constructeurs délégués
  • Délégation circulaire — erreur de compilation
  • Tentatives de déléguer l'appel au constructeur de la classe de base via un constructeur délégué

Exemple de la vie quotidienne

Cas négatif

Trois constructeurs, chacun initialisant explicitement des champs, la logique n'est pas synchronisée — une modification est apportée uniquement à un constructeur, les deux autres sont incorrects.

Avantages :

  • Simple à écrire

Inconvénients :

  • Risque élevé de divergence dans la logique entre les constructeurs

Cas positif

Un constructeur principal, les autres lui délèguent, toute la logique d'initialisation est centralisée.

Avantages :

  • Facilité de maintenance, divergence de logique exclue
  • Minimisation de la duplication de code

Inconvénients :

  • Il faut s'habituer à la syntaxe de la liste d'initialisation