2010-01-24 12 views
19

Problema:C++ eredità virtuale

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 
    /* ... */ 
}; 

Alla posizione data, gcc lamenta che non può abbinare la funzione di chiamata di Base(), vale a dire il costruttore di default. Ma C non eredita direttamente da Base, solo attraverso A e B. Allora perché gcc si lamenta qui?

Idee? TIA /Rob

+0

compilazione è fatto con no-RTTI set, potrebbe essere un problema? – Robert

+6

No, l'ereditarietà è una cosa in fase di compilazione, RTTI non sarà richiesto. – GManNickG

risposta

43

virtual le classi base sono speciali in quanto sono inizializzate dalla classe più derivata e non da qualsiasi classi di base intermedie che ereditano dalla base virtuale. Quale dei potenziali inizializzatori multipli sarebbe la scelta giusta per inizializzare l'unica base?

Se la classe più derivata in costruzione non la elenca nell'elenco di initalization dei membri, la classe di base virtuale viene inizializzata con il costruttore predefinito che deve esistere ed essere accessibile.

Si noti che un identificatore di base virtuale può essere utilizzato nella lista di inizializzazione di un costruttore anche se non è una base diretta della classe in questione.

+0

+1, Risposta più precisa :) –

+0

Addendum: Si noti che una classe astratta non può mai inizializzare la propria base virtuale, quindi non è necessario chiamare le basi virtuali ctor nella propria init-list dei vettori anche se non esiste alcun default-ctor. – Deduplicator

+0

Quindi questo significa che l'inizializzazione di A e B della classe genitore (cioè ": Base (pParent)") sono entrambe ignorate quando si costruisce la più classe derivata? – Chris

5

Se si dichiara un costruttore personalizzato, il costruttore predefinito è disabilitato. Nell'ereditarietà virtuale è necessario chiamare direttamente il costruttore virtualmente ereditato perché altrimenti non sarebbe sapere se inizializzare con A o con B.

7

È necessario chiamare esplicitamente il costruttore di base da C:

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

Non sapevo che potessi fare questo. Questo significa che il compilatore ignora il codice negli elementi di 'A' e' B' dove sembrano inizializzare 'Base'? – quamrana

+1

Non solo _can_ si fa questo, lo si deve fare. Nessun codice viene ignorato. Il costruttore di 'Base' sarà chiamato una sola volta, quindi il corpo dei costruttori per A e B, quindi il corpo del costruttore per C. – BenG

+0

Ora capisco l'ordine delle chiamate del costruttore e le ragioni dietro a questo, tranne I di solito hanno una classe base con solo un costruttore predefinito, quindi non devo avere chiamate esplicite a 'Base()'. Sicuramente, nell'esempio dall'OP, i compilatori devono ancora ignorare l'indicazione dei programmatori che 'Base (pParent)' dovrebbe essere chiamato direttamente dagli agenti di entrambi 'A' e' B'? – quamrana