2010-01-24 24 views
19

Problème:C++ héritage virtuel

class Base { 
public: 
    Base(Base* pParent); 
    /* implements basic stuff */ 
}; 

class A : virtual public Base { 
public: 
    A(A* pParent) : Base(pParent) {} 
    /* ... */ 
}; 

class B : virtual public Base { 
public: 
    B(B* pParent) : Base(pParent) {} 
    /* ... */ 
}; 

class C : public A, public B { 
public: 
    C(C* pParent) : A(pParent), B(pParent) {} // - Compilation error here 
    /* ... */ 
}; 

à la position donnée, gcc se plaint qu'il ne peut pas correspondre à l'appel de fonction à la base(), à savoir le constructeur par défaut. Mais C n'hérite pas directement de Base, seulement par A et B. Alors pourquoi gcc se plaint ici?

Des idées? TIA /Rob

+0

La compilation est faite sans-RTTI ensemble, peut-être un problème? – Robert

+6

Non, l'héritage est une chose à la compilation, RTTI ne sera pas nécessaire. – GManNickG

Répondre

43

virtual Les classes de base sont spéciales en ce qu'elles sont initialisées par la classe la plus dérivée et non par aucune classes de base intermédiaires qui héritent de la base virtuelle. Lequel des initiateurs multiples potentiels serait le bon choix pour initialiser la base?

Si la classe la plus dérivée en construction ne la liste pas dans sa liste d'initialisation de membre, alors la classe de base virtuelle est initialisée avec son constructeur par défaut qui doit exister et être accessible.

Notez qu'un identificateur de base virtuelle peut être utilisé dans la liste d'initialisation d'un constructeur même s'il ne s'agit pas d'une base directe de la classe en question.

+0

+1, réponse la plus précise :) –

+0

Addendum: Notez qu'une classe abstraite ne peut jamais initialiser sa base virtuelle, il n'est donc pas nécessaire d'appeler les bases virtuelles ctor dans sa liste d'init de ctors même s'il n'existe pas de default-ctor. – Deduplicator

+0

Cela signifie donc que l'initialisation A et B de la classe parent (c'est-à-dire ': Base (pParent)') est ignorée lors de la construction de la classe plus dérivée? – Chris

5

Si vous déclarez un constructeur personnalisé, le constructeur par défaut est désactivé. Dans l'héritage virtuel, vous devez appeler le constructeur virtuellement hérité directement car sinon il ne sait pas s'il faut initialiser par A ou par B.

7

Vous devez appeler explicitement le constructeur de base de C:

class C : public A, public B { 
public: 
C(C* pParent) : Base(pParent), A(pParent), B(pParent) {} 
/*... */ 
}; 
+0

Je ne savais pas que tu pouvais le faire. Cela signifie-t-il que le compilateur ignore le code dans les vecteurs de 'A' et' B' où ils semblent initialiser 'Base'? – quamrana

+1

Non seulement vous pouvez le faire, vous devez le faire. Aucun code n'est ignoré. Le constructeur de 'Base' ne sera appelé qu'une seule fois, puis le corps des constructeurs de A et B, puis le corps du constructeur de C. – BenG

+0

Je comprends maintenant l'ordre des appels constructeurs et les raisons derrière cela, sauf que je ont généralement une classe de base avec seulement un constructeur par défaut, donc je n'ai pas besoin d'avoir des appels explicites à 'Base()'. Sûrement, dans l'exemple de l'OP, les compilateurs doivent toujours ignorer l'indication des programmeurs que 'Base (pParent)' devrait être appelé directement depuis les '' A' et 'B'? – quamrana