Warum wird der Standardkonstruktor bei der virtuellen Vererbung aufgerufen?


79

Ich verstehe nicht, warum im folgenden Code, wenn ich ein Objekt vom Typ instanziiere daughter, der Standardkonstruktor grandmother()aufgerufen wird.

Ich dachte, dass entweder der grandmother(int)Konstruktor aufgerufen werden sollte (um der Spezifikation meines motherKlassenkonstruktors zu folgen ), oder dass dieser Code wegen der virtuellen Vererbung überhaupt nicht kompiliert werden sollte.

Hier ruft der Compiler stillschweigend den grandmotherStandardkonstruktor in meinem Rücken auf, während ich nie danach gefragt habe.

#include <iostream>

class grandmother {
public:
    grandmother() {
        std::cout << "grandmother (default)" << std::endl;
    }
    grandmother(int attr) {
        std::cout << "grandmother: " << attr << std::endl;
    }
};

class mother: virtual public grandmother {
public:
    mother(int attr) : grandmother(attr) {
        std::cout << "mother: " << attr << std::endl;
    }
};

class daughter: virtual public mother {
public:
    daughter(int attr) : mother(attr) {
        std::cout << "daughter: " << attr << std::endl;
    }
};

int main() {
  daughter x(0);
}

Welcher Compiler (und welche Version)? Mit welchen Argumenten haben Sie es zusammengestellt?
Orlp

gcc 4.6.3 20120306 (Red Hat 4.6.3-2) auf Fedora 15. Argumente sind: -O0 -g3 -Wall -c -fmessage-length = 0
Simon Desfarges

g ++ 4.1.2 hat das gleiche Problem: codepad.org/L0jBXfSP
orlp

Ubuntu 4.7 Snapshot mit -Wall -pedantic-Fehlern reproduziert dies.
Juanchopanza

Antworten:


85

Bei Verwendung der virtuellen Vererbung wird der Konstruktor der virtuellen Basisklasse direkt vom Konstruktor der am meisten abgeleiteten Klasse aufgerufen. In diesem Fall daughterruft der grandmotherKonstruktor den Konstruktor direkt auf .

Da Sie den grandmotherKonstruktor in der Initialisierungsliste nicht explizit aufgerufen haben , wird der Standardkonstruktor aufgerufen. Um den richtigen Konstruktor aufzurufen, ändern Sie ihn in:

daugther(int attr) : grandmother(attr), mother(attr) { ... }

Siehe auch Dieser FAQ-Eintrag .


2
Das macht total Sinn, danke! Alle Konstruktoren in der Hierarchie werden von der letzten Klasse und nicht von ihrer jeweiligen untergeordneten Klasse aufgerufen. Daran habe ich nie gedacht. C ++ - Spezifikation kann manchmal schwierig sein ...
Aurelien Ribon

1
Hervorragende Antwort! Danke!
Pat Mustard

1
@Xriuk Es bezieht sich auf Konstruktoren von Klassen, die mithilfe der virtuellen Vererbung geerbt wurden.
Interjay

1
Bedeutet das, dass Großmutter zweimal angerufen wird? Was passiert mit dem Anruf bei der Großmutter in der Mutter?
Youda008

5
@ Youda008 Es wird einmal aufgerufen. Der Aufruf von motherwird ignoriert, es sei denn, Sie instanziieren direkt motherund nicht eine abgeleitete Klasse.
Interjay
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.