1019 votes

Puis-je appeler un constructeur à partir d'un autre constructeur (faire du chaînage de constructeurs) en C++ ?

En tant que C# développeur je suis habitué à courir à travers les constructeurs :

class Test {
    public Test() {
        DoSomething();
    }

    public Test(int count) : this() {
        DoSomethingWithCount(count);
    }

    public Test(int count, string name) : this(count) {
        DoSomethingWithName(name);
    }
}

Existe-t-il un moyen de faire cela en C++ ?

J'ai essayé d'appeler le nom de la classe et d'utiliser le mot-clé "this", mais les deux échouent.

0 votes

Utilisation de this OU auto dans le contexte référencé seraient des mots-clés intéressants à des fins de refactoring futur.

1359voto

JohnIdol Points 16355

C++11 : Oui !

Les versions C++11 et ultérieures disposent de cette même fonctionnalité (appelée délégation des constructeurs ).

La syntaxe est légèrement différente de celle du C# :

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {}
};

C++03 : Non

Malheureusement, il n'y a aucun moyen de le faire en C++03, mais il y a deux façons de le simuler :

  1. Vous pouvez combiner deux constructeurs (ou plus) via des paramètres par défaut :

    class Foo {
    public:
      Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
      // ...
    };
  2. Utilisez une méthode init pour partager un code commun :

    class Foo {
    public:
      Foo(char x);
      Foo(char x, int y);
      // ...
    private:
      void init(char x, int y);
    };
    
    Foo::Foo(char x)
    {
      init(x, int(x) + 7);
      // ...
    }
    
    Foo::Foo(char x, int y)
    {
      init(x, y);
      // ...
    }
    
    void Foo::init(char x, int y)
    {
      // ...
    }

Ver l'entrée C++FAQ pour référence.

84 votes

En fait, les paramètres remarquablement par défaut permettent de très propre pour faire ce que l'on fait habituellement en appelant this() en C#.

5 votes

Notez que la solution proposée de ne pas utiliser C++11 ne fonctionne que si la classe à construire n'a pas d'héritage ni de champs constants. Je n'ai pas trouvé de moyen d'initialiser la classe mère et les champs constants en dehors de la liste d'initialisation.

0 votes

Merci pour votre réponse. Un point important à noter est qu'un tel code sera compilé et exécuté. L'une des réponses ci-dessous souligne ce point. Ce serait bien si vous pouviez mettre un lien vers la réponse ci-dessous également, car la plupart des gens ne voient que la première réponse.

125voto

Cyrille Ka Points 8845

Oui et non, selon la version de C++.

En C++03, vous ne pouvez pas appeler un constructeur à partir d'un autre (appelé constructeur de délégation).

Cela a changé dans le C++11 (alias C++0x), qui a ajouté la prise en charge de la syntaxe suivante :
(exemple tiré de Wikipedia )

class SomeType
{
  int number;

public:
  SomeType(int newNumber) : number(newNumber) {}
  SomeType() : SomeType(42) {}
};

3 votes

Mais en quoi cela diffère-t-il de la syntaxe standard des paramètres par défaut ?

0 votes

@TomášZato Une chose que vous ne pouvez pas faire avec les paramètres par défaut est d'utiliser votre paramètre pour appeler l'autre constructeur : SomeType(string const &s) { /*...*/ } SomeType(char const *pc) : SomeType(string(pc)) { /*...*/ }

7 votes

@TomášZato Une autre différence est qu'avec les paramètres par défaut, vous n'avez qu'un seul constructeur que vous devez rendre soit public, soit protégé, soit privé, alors qu'avec deux constructeurs, l'un appelant l'autre, vous pouvez restreindre l'accès à l'un d'eux sans avoir à restreindre également l'accès à l'autre.

49voto

ohlemacher Points 198

Je crois que vous pouvez appeler un constructeur à partir d'un constructeur. Il sera compilé et exécuté. J'ai récemment vu quelqu'un faire cela et cela a fonctionné à la fois sur Windows et Linux.

Il ne fait tout simplement pas ce que vous voulez. Le constructeur interne construira un objet local temporaire qui sera supprimé dès le retour du constructeur externe. Il faudrait aussi qu'ils soient des constructeurs différents, sinon vous créeriez un appel récursif.

Réf : https://isocpp.org/wiki/faq/ctors#init-methods

3 votes

Bon point ; la plupart ont juste dit "non vous ne pouvez pas". Moi je peux :). J'ai fait cette commutation en arrière et j'utilisais le ctor original pour décider quel autre appeler. En débogage, l'objet peut être vu dans le second, tout est initialisé mais revient aux valeurs par défaut lorsqu'il est retourné. Cela a beaucoup de sens quand on y pense.

11 votes

Ce n'est pas "appeler un constructeur". Le site seulement L'endroit où l'on peut "appeler un constructeur" directement est dans la section ctor-initialisateur Ce que vous faites dans cet exemple est la construction d'un objet, ce qui est une autre paire de manches. Ne vous laissez pas tromper par le fait qu'il s'agit de regarde comme un appel de fonction au constructeur, car il est pas un ! Il n'y a en fait aucun moyen de faire un appel de fonction au constructeur, c'est pourquoi il est impossible de construire une instance d'une classe dont le(s) seul(s) constructeur(s) sont des instanciations d'un modèle de fonction dont les arguments de modèle ne peuvent être déduits.

1 votes

(C'est-à-dire qu'il est syntaxiquement impossible de fournir explicitement des arguments de modèle à un constructeur).

29voto

kchoose2 Points 140

C++11 : Oui !

Les versions C++11 et ultérieures disposent de cette même fonctionnalité (appelée délégation des constructeurs ).

La syntaxe est légèrement différente de celle du C# :

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {}
};

C++03 : Non

Il est utile de souligner que vous peut appeler le constructeur d'une classe parente dans votre constructeur, par exemple :

 class A { /* ... */ };

    class B : public A
    {
        B() : A()
        {
            // ...
        }
    };

Mais, non, vous ne pouvez pas appeler un autre constructeur de la même classe jusqu'à C++03.

0 votes

Vous avez tort. Vous pouvez appeler un constructeur de la même classe. Il sera déterminé quel constructeur appeler en utilisant sa liste d'arguments. Faire B(int x, inty) : B(x) appellera d'abord le constructeur avec la signature B(int x).

16 votes

Oui. Mais j'avais raison en novembre 2008, avant la publication de C++11.

22voto

Ben L Points 580

Sur C++11 , a Le constructeur peut appeler une surcharge d'un autre constructeur :

class Foo  {
     int d;         
public:
    Foo  (int i) : d(i) {}
    Foo  () : Foo(42) {} //New to C++11
};

De plus, les membres peuvent être initialisés de cette manière.

class Foo  {
     int d = 5;         
public:
    Foo  (int i) : d(i) {}
};

Cela devrait éliminer la nécessité de créer la méthode d'aide à l'initialisation. Et il est toujours recommandé de ne pas appeler de fonctions virtuelles dans les constructeurs ou les destructeurs pour éviter d'utiliser des membres qui pourraient ne pas être initialisés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X