Ordine di chiamata del costruttore nell’eredità virtuale

class A { int i; public: A() {cout<<"in A's def const\n";}; A(int k) {cout<<"In A const\n"; i = k; } }; class B : virtual public A { public: B(){cout<<"in B's def const\n";}; B(int i) : A(i) {cout<<"in B const\n";} }; class C : public B { public: C() {cout<<"in C def cstr\n";} C(int i) : B(i) {cout<<"in C const\n";} }; int main() { C c(2); return 0; } 

L’output in questo caso è

 in A's def const in B const in C const 

Perché questo non sta entrando in in A const

`Dovrebbe seguire l’ordine della chiamata del costruttore di 1 arg. Ma cosa sta realmente accadendo nel derivare B da A usando una parola chiave virtuale.

Ci sono poche altre domande

Anche se rimuovo la parola chiave virtuale nel programma di cui sopra e rimuovo tutto il costruttore predefinito che dà errore. Quindi, perché ha bisogno del costruttore def

    I costruttori per le classi di base virtuali vengono sempre chiamati dalla class più derivata, utilizzando qualsiasi argomento che potrebbe passare. Nel tuo caso, la class più derivata non specifica un inizializzatore per A , quindi viene utilizzato il costruttore predefinito.

    Come JamesKanze ha spiegato , in caso di ereditarietà virtual è la class più derivata che chiama il costruttore della class base virtuale. Quindi, se si desidera che il costruttore di A abbia un numero intero da chiamare, è necessario aggiungerlo all’elenco di inizializzazione di C

     C(int i) : A(i), B(i) {cout<<"in C const\n";} 

    Per la seconda parte della domanda, i costruttori predefiniti non sono obbligatori, ma la class derivata deve chiamare esplicitamente il costruttore non predefinito, poiché il compilatore non è in grado di farlo automaticamente in assenza di un costruttore non predefinito.

     #include  using namespace std; class A { int i; public: // A() {cout<<"in A's def const\n";}; A(int k) {cout<<"In A const\n"; i = k; } }; class B : virtual public A { public: // B(){cout<<"in B's def const\n";}; B(int i) : A(i) {cout<<"in B const\n";} }; class C : public B { public: C() : A(42), B(42) {cout<<"in C def cstr\n";} C(int i) : A(i), B(i) {cout<<"in C const\n";} }; int main() { C c(2), c2; return 0; } 

    Questo stampa

     In A const in B const in C const In A const in B const in C def cstr 

    Ci sono due domande qui.

    Perché non sta entrando in A const?

    Perché stai usando l’ereditarietà virtuale.

    Quando si utilizza l’ereditarietà virtuale, l’ elenco Inizializzazione del ctor della maggior parte della class derivata richiama direttamente il ctor della class base virtuale. . In questo caso, ciò significa che il costruttore di C chiama direttamente il costruttore di A Dato che non hai specificato quale costruttore A chiamare nella lista di inizializzazione di C , viene chiamato il costruttore predefinito.

    Questo problema viene risolto cambiando l’implementazione di C::C(int) in:

     C(int i) : A(i), B(i) {cout<<"in C const\n";} 

    Se rimuovo la parola chiave virtuale nel programma di cui sopra e rimuovo tutto il costruttore predefinito che genera un errore. Quindi, perché ha bisogno del def costruttore?

    Perché anche B non specifica quale A ctor chiamare, quindi viene utilizzato il costruttore predefinito. Se si rimuove il difetto di A, B non può essere compilato.