23

Dies ist der Code:Mixing virtuelle und nicht virtuelle Vererbung einer Basisklasse

struct Biology 
{  
    Biology() { cout << "Biology CTOR" << endl; } 
}; 

struct Human : Biology 
{  
    Human() { cout << "Human CTOR" << endl; } 
}; 

struct Animal : virtual Biology 
{ 
    Animal() { cout << "Animal CTOR" << endl; } 
}; 

struct Centaur : Human, Animal 
{ 
    Centaur() { cout << "Centaur CTOR" << endl; } 
}; 

int main() 
{ 
    Centaur c; 

    return 0; 
} 

Dieser Code druckt:

Biology CTOR 
Biology CTOR 
Human CTOR 
Animal CTOR 
Centaur CTOR 

Warum?

Da wir ein Centaur Objekt zu erstellen, starten wir vom Aufbau der Centaur von Human Konstruktion, Animal und schließlich Centaur (wir gehen von dem weniger abgeleitet auf die meisten abgeleitet).

des von Human Beginnen wir: Human erbt von Biology, also nennen wir Biology ‚s Konstruktor zuerst. Nun, da die Basisklasse Human konstruiert ist, können wir endlich die Human selbst konstruieren. Aber stattdessen wird Biology wieder aufgebaut!

Warum? Was passiert hinter den Kulissen?

Bitte beachten Sie, dass es völlig beabsichtigt war Animal verlassen zugleich praktisch von Biology und vererben, ist es auch beabsichtigt war praktisch nicht von Biology vererben Human verlassen.

Wir lösen die Dreaded Diamant in einer falschen Art und Weise: Mensch und Tier praktisch Biologie erben sollte, um diese Arbeit zu machen.

Ich bin nur neugierig.

Auch hierzu finden Sie diesen Code:

struct Biology 
{  
    Biology() { cout << "Biology CTOR" << endl; } 
}; 

struct Human : virtual Biology 
{ 
    Human() { cout << "Human CTOR" << endl; } 
}; 

struct Animal : Biology 
{  
    Animal() { cout << "Animal CTOR" << endl; } 
}; 

struct Centaur : Human, Animal 
{ 
    Centaur() { cout << "Centaur CTOR" << endl; } 
}; 

int main() 
{ 
    Centaur c; 

    return 0; 
} 

Hier haben wir Human praktisch von Biology vererben, während Animal eingestellt ist in den "klassischen Weg" erben.

Aber diesmal ist der Ausgang anders:

Biology CTOR 
Human CTOR 
Biology CTOR 
Animal CTOR 
Centaur CTOR 

Dies, weil Centaur inherits zunächst von Human und dann von Animal.

Wäre die Reihenfolge umgekehrt, hätten wir im ersten Beispiel das gleiche Ergebnis wie zuvor erzielt - zwei Biology Instanzen, die in einer Reihe aufgebaut sind.

Was ist die Logik davon?

Bitte versuchen Sie, Ihren Weg zu erklären, ich habe schon Tonnen von Websites überprüft, die darüber sprechen. Aber keiner scheint meine Bitte zu erfüllen.

+2

Was für eine ausgezeichnete Frage! – Hexaholic

Antwort

36

Es ist klar von der Ausgabe, dass zwei Biology Objekte instanziiert werden.Das ist, weil Sie nur eine Vererbung virtual gemacht haben. Zwei Basisklasseninstanzen sind die Ursache für Mehrdeutigkeit in gefürchtetem Diamantproblem und die Lösung besteht darin, (wie wir wissen) beide Erbschaften von Biologyvirtual zu machen.

Recap der Hierarchie:

Biology Biology 
    |  |  # one and only one inheritance virtual 
Human  Animal 
    \ /
    Centaur 

Ok, lassen Sie sich die Ausgabe wieder mit diesen Regeln in Gedanken lesen:

  • Basisklassen aufgebaut werden, bevor abgeleiteten Klassen.
  • Basisklassen werden in der Reihenfolge erstellt, in der sie in der Base-Specifier-Liste erscheinen.
  • Virtuelle Basisklassen werden vor nicht virtuellen durch die am weitesten abgeleitete Klasse - see this erstellt.

1. Ausgabe - Animalvirtual erbt ly aus Biology:

Biology CTOR  # virtual base class inherited from Animal 
Biology CTOR  # non-virtual base class of Human 
Human CTOR  # Human itself 
Animal CTOR  # Animal's virtual base class already constructed 
Centaur CTOR 

2. Ausgabe - Humanvirtual ly erbt von Biology:

Biology CTOR  # virtual base class inherited from Human 
Human CTOR  # Human's virtual base class already constructed 
Biology CTOR  # non-virtual base class of Animal 
Animal CTOR  # Animal itself 
Centaur CTOR 

Informativer Standard Absatz ([class.base.init]/10) :

In einem nicht delegieren Konstruktor Initialisierung erfolgt in den folgende Reihenfolge:

- Erste und nur für den Konstruktor der meisten abgeleiteten Klasse (1.8) werden virtuelle Basisklassen in der Reihenfolge initialisiert, erscheinen sie auf einer Tiefen-zuerst-links-nach-rechts-Traversierung des gerichteten azyklischen Graphen der Basisklassen , wobei "von links nach rechts" die Reihenfolge Aussehen der Basis ist Klassen in der abgeleiteten Klasse Basisspezifizierer-Liste.

- Dann direkte Basisklassen initialisiert werden in Erklärung Reihenfolge, wie sie in der Basis-Bezeichner-Liste (unabhängig von der Reihenfolge des mem-initializers) erscheinen.

...

+1

Diese Antwort ist Gold. Danke;) – gedamial

2

Nicht virtuelle Vererbung ist eine exklusive Beziehung, wie Mitgliedschaft. Eine Klasse kann die nicht-virtuelle Basisklasse einer anderen Klasse in einem gegebenen vollständigen Objekt sein.

Dies bedeutet, dass eine Klasse virtuelle Funktionen einer nicht virtuellen Basisklasse überschreiben kann, ohne Konflikte oder Probleme zu verursachen.

Ein Konstruktor kann auch nicht virtuelle Basen zuverlässig initialisieren.

Nur virtuelle Basen können direkte Basisklassen vieler indirekter Basen eines vollständigen Objekts sein. Da eine virtuelle Basisklasse gemeinsam genutzt werden kann, können Übersteuerungen einen Konflikt verursachen.

Ein Konstruktor kann versuchen, ein virtuelles Basis-Subobjekt in der ctor-init-Liste zu initialisieren, aber wenn die Klasse weiter abgeleitet wird, wird dieser Teil der ctor-init-Liste ignoriert.

1
  1. Alle Basisklassen, die zwischen ihnen praktisch von Biology Aktien eine Instanz Biology Basis erben.
  2. Alle Basisklassen, die nicht virtuell von Biology erben, haben jeweils eine Instanz Biology.

Sie haben eine Basis in jeder Kategorie, damit Sie haben eine Instanz Biology von Human gebracht (und im Prinzip mit anderen geteilt werden) und einer Instanz von Animal (niemals mit einer anderen Basisklasse gemeinsam) gebracht.

+0

Danke für die Antwort, obwohl nach einem Jahr haha – gedamial

Verwandte Themen