web-dev-qa-db-fra.com

Héritage des constructeurs

Pourquoi ce code:

class A
{
    public: 
        explicit A(int x) {}
};

class B: public A
{
};

int main(void)
{
    B *b = new B(5);
    delete b;
}

Résultat de ces erreurs:

 main.cpp: Dans la fonction 'int main ()': 
 main.cpp: 13: erreur: pas de fonction correspondante pour l'appel à 'B :: B (int)' 
 main.cpp: 8: remarque: les candidats sont: B :: B () 
 main.cpp: 8: remarque: B :: B (const B &) 

B ne devrait-il pas hériter du constructeur de A?

(ceci utilise gcc)

195
Sydius

Si votre compilateur prend en charge le standard C++ 11, il existe un héritage de constructeur utilisant using (jeu de mots voulu). Pour plus d'informations, voir article de Wikipedia C++ 11 . Vous écrivez:

class A
{
    public: 
        explicit A(int x) {}
};

class B: public A
{
     using A::A;
};

Ceci est tout ou rien - vous ne pouvez pas hériter que de certains constructeurs, si vous écrivez ceci, vous héritez tous. Pour hériter uniquement des éléments sélectionnés, vous devez écrire les constructeurs individuels manuellement et appeler le constructeur de base selon vos besoins.

Historiquement, les constructeurs ne pouvaient pas être hérités dans la norme C++ 03. Vous deviez en hériter manuellement un par un en appelant vous-même l'implémentation de base.

348
Suma

Les constructeurs ne sont pas hérités. Ils sont appelés implicitement ou explicitement par le constructeur enfant.

Le compilateur crée un constructeur par défaut (un sans arguments) et un constructeur de copie par défaut (un avec un argument qui fait référence au même type). Mais si vous voulez un constructeur qui acceptera un int, vous devez le définir explicitement.

class A
{
public: 
    explicit A(int x) {}
};

class B: public A
{
public:
    explicit B(int x) : A(x) { }
};

UPDATE: En C++ 11, les constructeurs peuvent être hérités. Voir la réponse de Suma pour plus de détails.

84
Avi

Vous devez définir explicitement le constructeur dans B et appeler explicitement le constructeur pour le parent.

B(int x) : A(x) { }

ou

B() : A(5) { }
7
grepsedawk

Pourquoi ne pas utiliser une fonction template pour lier tous les constructeurs?

template <class... T> Derived(T... t) : Base(t...) {}
4
Pradu

Ceci est directement de la page de Bjarne Stroustrup :

Si vous le souhaitez, vous pouvez toujours vous tirer d'affaire en héritant des constructeurs d'une classe dérivée dans laquelle vous définissez de nouvelles variables de membre nécessitant une initialisation:

struct B1 {
    B1(int) { }
};

struct D1 : B1 {
    using B1::B1; // implicitly declares D1(int)
    int x;
};

void test()
{
    D1 d(6);    // Oops: d.x is not initialized
    D1 e;       // error: D1 has no default constructor
}
4
nenchev

Le code correct est

class A
{
    public: 
      explicit A(int x) {}
};

class B: public A
{
      public:

     B(int a):A(a){
          }
};

main()
{
    B *b = new B(5);
     delete b;
}

Error is b/c La classe B n'a pas de constructeur de paramètre et, en second lieu, elle doit avoir un initialiseur de classe de base pour appeler le constructeur du constructeur de paramètre de classe de base.

2
Iqbal Haider