2010-07-18 15 views
1

Problème étrange est survenu lorsque j'ai essayé de « résoudre » problème de diamant d'habitude de manière habituelle - en utilisant l'héritage virtuel:sous-problème diamant: héritage non multiple dans la branche latérale nécessitent encore constructeur de la classe

A 
/\* both virtual 
B C 
\/
    D 

Cependant, mon classe de base a ne pas constructeur par défaut, donc je devais l'appeler manuellement D. Cependant, lorsque je tente d'ajouter une classe E dans ce diamant C-hérité

A 
/\* both virtual 
B C 
\/\ 
    D E 

il est encore nécessaire pour constructeur appeler de A dans le constructeur E manuellement, c'est-à-dire que C ne sait pas quoi créer A à partir de E même ough il n'y a ni héritage multiple ni diamant A-C-E. Est-il possible de résoudre ce problème sans appeler le constructeur de A à partir de E?

class A      
    {public: 
     A (int _N): N(_N) {}; 
     void show() 
     {cout<<"A"<<N;} 
    protected: 
     int N; 
    }; 
class B: public virtual A 
    { public: 
     B(int n): A(2*n) {}; 
     void show() 
     { cout<<"B"<<N;} 
    }; 
class C: public virtual A 
    { public: 
     C(int n): A(3*n) {}; 
     void show() 
     { cout<<"C"<<N;} 
    }; 
class D: public B,C 
    { public: 
     D(): B(1), C(2), A(3) {}; 
     void show() 
     { cout<<"D"<<N;} 
    }; 

class E: public virtual C 
    { public: 
     E(): C(1) {}; 
     void show() 
     { cout<<"E"<<N;} 
    }; 

int main() 
    {D d;  // OK 
    A *a = &d; 
    a->show(); 

    E e;  // NOT OK, no function A::A() to call in E::E() 
    A *a2 = &e; 
    a2->show(); 
    return 0; 
    } 
J'ai besoin de C pour le faire correctement :-).

Ou est-il possible de ne pas essayer de résoudre le problème de diamant du tout:

A A 
| | no virtual at all 
B C 
\/\ 
    D E 

et toujours essayer de déclarer objet de la classe D avec deux instances de A mais compilateur dire d'utiliser un C quand Colling de D chaque fois? Lorsque je tente d'ajouter

using C::A 

dans la déclaration de D, il produit encore erreur de la base non ambiguë A.

Répondre

2

Est-il possible de résoudre ce problème sans appeler le constructeur de A de E? J'ai besoin de C pour le faire correctement :-).

Le constructeur de la classe la plus dérivée (dans ce cas, E) est responsable d'appeler le constructeur pour toutes les classes de base virtuelles.

Le constructeur de C ne peut pas appeler le constructeur de A car C n'est pas la classe la plus dérivée. Les classes de base virtuelles sont initialisées avant les classes de base directes, donc E doit être initialisé par A avant de pouvoir initialiser C.

+0

Merci, cela est compréhensible, est-ce que cette signification exacte de l'héritage virtuel? Maintenant, je vois. Probablement je n'ai pas besoin d'héritage virtuel ici, malheureusement ça ne sera pas confortable (car il y a beaucoup de dérivées de E et chacune devrait appeler un constructeur de la même manière que C et ainsi de suite). Peut-être existe-t-il un moyen de contourner le problème du diamant sans héritage virtuel (d'une manière similaire à l'utilisation)? – Nick

+0

@Nick: C'est un peu difficile à dire avec un exemple abstrait comme celui-ci. Pour être honnête, j'évite généralement les hiérarchies d'héritage complexes dans le code que j'écris. Quelqu'un d'autre pourrait avoir une bonne solution pragmatique pour le cas général. –

+0

Je pensais ... eh bien, je n'ai pas besoin que C soit l'enfant de A autant dans mon cas particulier. E pourrait être l'enfant direct de A (avec C) à la place. @James, merci encore beaucoup. – Nick

2

Oui, les appels constructeur de classe de base virtuelle ne sont pas comme fonction primordiale virtuelle:

  • vous pouvez remplacer une fonction virtuelle dans une classe dérivée; Remplacez une fonction virtuelle uniquement si la fonction est remplacée dans l'une des classes de base mais pas dans d'autres;
  • vous ne pouvez pas remplacer la init-list pour les classes de base virtuelles du constructeur de classe de base.

Cela implique que:

  • dans la mesure prioritaire de fonction virtuelle est concernée, l'héritage virtuel n'affecte pas l'héritage unique du tout;
  • mais quand il s'agit d'appels de constructeurs de classe de base, l'héritage virtuel affecte chaque classe dérivée.