web-dev-qa-db-fra.com

Vous utilisez des constructeurs de classe de base C ++?

En travaillant avec des modèles, j'ai rencontré un besoin de rendre les constructeurs de classes de base accessibles à partir des classes héritées pour la création d'objets afin de réduire les opérations de copier/coller. Je pensais faire cela par le biais du mot clé using de la même manière avec le cas des fonctions, mais cela ne fonctionne pas.

class A
{
public: 
    A(int val) {}
};

class B : public A
{
};

class C : public A
{
public:
    C(const string &val) {}
};

class D : public A
{
public:
    D(const string &val) {}
    using A::A;              // g++ error: A::A names constructor
};

void main()
{
    B b(10);                // Ok.   (A::A constructor is not overlapped)
    C c(10);                // error: no matching function to call to 'C::C(int)'
}

Donc, ma question: existe-t-il un moyen d'importer des constructeurs de classe de base après que de nouveaux dans la classe héritée aient été déclarés?

Ou il n'y a qu'une seule alternative pour déclarer de nouveaux constructeurs et appeler ceux de base à partir de la liste d'initialisation?

49
minyor

Préférez l'initialisation:

class C : public A
{
public:
    C(const string &val) : A(anInt) {}
};

En C++ 11, vous pouvez utiliser des constructeurs hérités (dont la syntaxe est visible dans votre exemple D).

Mise à jour: Les constructeurs hérités sont disponibles dans GCC depuis la version 4.8.


Si vous ne trouvez pas l'initialisation attrayante (par exemple en raison du nombre de possibilités dans votre cas réel), alors vous pourriez privilégier cette approche pour certaines constructions TMP:

class A
{
public: 
    A() {}
    virtual ~A() {}
    void init(int) { std::cout << "A\n"; }
};

class B : public A
{
public:
    B() : A() {}
    void init(int) { std::cout << "B\n"; }
};

class C : public A
{
public:
    C() : A() {}
    void init(int) { std::cout << "C\n"; }
};

class D : public A
{
public:
    D() : A() {}
    using A::init;
    void init(const std::string& s) { std::cout << "D -> " << s << "\n"; }
};

int main()
{
    B b; b.init(10);
    C c; c.init(10);
    D d; d.init(10); d.init("a");

    return 0;
}
37
justin

Oui, depuis C++ 11:

struct B2 {
    B2(int = 13, int = 42);
};
struct D2 : B2 {
    using B2::B2;
// The set of inherited constructors is
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()

// D2 has the following constructors:
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- inherited
// 5. D2(int) <- inherited
};

Pour plus d'informations, voir http://en.cppreference.com/w/cpp/language/using_declaration

55
Sergei

Non, ce n'est pas comme ça que ça se fait. La manière normale d'initialiser la classe de base est dans la liste d'initialisation:

class A
{
public: 
    A(int val) {}
};

class B : public A
{
public:
  B( int v) : A( v )
  {
  }
};


void main()
{
    B b(10);
}
8
BЈовић

Vous devrez déclarer des constructeurs dans chacune des classes dérivées, puis appeler le constructeur de la classe de base à partir de la liste d'initialisation:

class D : public A
{
public:
    D(const string &val) : A(0) {}
    D( int val ) : A( val ) {}
};

D variable1( "Hello" );
D variable2( 10 );

C++ 11 vous permet d'utiliser la syntaxe utilisant A :: A que vous utilisez dans votre déclerération de D, mais les fonctionnalités C++ 11 ne sont pas prises en charge par tous les compilateurs pour le moment, il est donc préférable de s'en tenir aux anciennes méthodes C++ jusqu'à ce que cela est implémentée dans tous les compilateurs avec lesquels votre code sera utilisé.

4
obmarg

Voici une bonne discussion sur règles d'appel du constructeur de superclasse . Vous voulez toujours que le constructeur de la classe de base soit appelé avant le constructeur de la classe dérivée afin de former correctement un objet. C'est pourquoi ce formulaire est utilisé

  B( int v) : A( v )
  {
  }
1
jbat100