Question Puis-je appeler un constructeur à partir d'un autre constructeur (faire un constructeur en chainage) en C ++?


Comme un 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);
    }
}

Y a-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.


756
2017-11-21 09:43


origine


Réponses:


C ++ 11: Oui!

C ++ 11 et suivantes a cette même fonctionnalité (appelée déléguer des constructeurs).

La syntaxe est légèrement différente de 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 simuler ceci:

  1. Vous pouvez combiner deux (ou plusieurs) constructeurs via les 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 le 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)
    {
      // ...
    }
    

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


1020
2017-11-21 10:04



Non, vous ne pouvez pas appeler un constructeur d'un autre en C ++ 03 (appelé un constructeur délégué).

Cela a changé dans C ++ 11 (aka C ++ 0x), qui a ajouté le support de la syntaxe suivante:
(exemple tiré de Wikipédia)

class SomeType
{
  int number;

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

101
2017-11-21 10:00



Je crois que vous pouvez appeler un constructeur d'un constructeur. Il compilera et fonctionnera. J'ai récemment vu quelqu'un faire cela et il a fonctionné sur Windows et Linux.

Ça ne fait pas ce que tu veux. Le constructeur interne construira un objet local temporaire qui sera supprimé une fois que le constructeur externe sera retourné. Ils devraient aussi être des constructeurs différents ou créer un appel récursif.

Ref: https://isocpp.org/wiki/faq/ctors#init-methods


38
2017-08-12 15:31



Il vaut la peine de souligner que vous pouvez appelez 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.


19
2017-11-22 06:36



Dans C ++ 11, une constructeur peut appeler une autre surcharge du 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 comme ça.

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

Cela devrait éliminer le besoin de créer la méthode d'assistance d'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.


17
2017-09-22 20:07



Si vous voulez être mauvais, vous pouvez utiliser le "nouvel" opérateur sur place:

class Foo() {
    Foo() { /* default constructor deliciousness */ }
    Foo(Bar myParam) {
      new (this) Foo();
      /* bar your param all night long */
    } 
};

Ça semble fonctionner pour moi.

modifier

Comme le souligne @ElvedinHamzagic, si Foo contenait un objet qui allouait de la mémoire, cet objet pourrait ne pas être libéré. Cela complique les choses plus loin.

Un exemple plus général:

class Foo() {
private:
  std::vector<int> Stuff;
public:
    Foo()
      : Stuff(42)
    {
      /* default constructor deliciousness */
    }

    Foo(Bar myParam)
    {
      this->~Foo();
      new (this) Foo();
      /* bar your param all night long */
    } 
};

Ça a l'air un peu moins élégant, c'est sûr. @ La solution de JohnIdol est beaucoup mieux.


11
2018-03-24 16:53



Non, en C ++, vous ne pouvez pas appeler un constructeur à partir d'un constructeur. Ce que vous pouvez faire, comme l'a souligné warren, c'est:

  • Surcharger le constructeur, en utilisant différentes signatures
  • Utiliser les valeurs par défaut sur les arguments, pour rendre une version "plus simple" disponible

Notez que dans le premier cas, vous ne pouvez pas réduire la duplication de code en appelant un constructeur d'un autre. Vous pouvez bien sûr avoir une méthode séparée, privée / protégée, qui effectue toute l'initialisation et laisse le constructeur s'occuper principalement de la gestion des arguments.


7
2017-11-21 09:56