2016-07-29 87 views
2

Im Lesen this Artikel über Konstruktoren für C++C++ virtuelle Funktion in Konstruktor

Wir empfehlen, dass Sie vorsichtig sein, wenn Sie virtuelle Funktionen in Bauer nennen. Da der Basisklassenkonstruktor immer vor dem abgeleiteten Klassenkonstruktor aufgerufen wird, ist die Funktion, die in der Basiskonstruktor aufgerufen wird, die Basisklassenversion, nicht die abgeleitete Klasse Version. Im folgende Beispiel wird die Konstruktion eines DerivedClass verursacht Die Basisklasse Umsetzung print_it() auszuführen, bevor der DerivedClass Konstruktor die DerivedClass Umsetzung print_it Ursachen() auszuführen:

das Beispiel:

class BaseClass { 
    public: 
     BaseClass() { 
      print_it(); 
     } 
     virtual void print_it() { 
      cout << "BaseClass print_it" << endl; 
     } 
    }; 

    class DerivedClass : public BaseClass { 
    public: 
     DerivedClass() { 
      print_it(); 
     } 
     virtual void print_it() { 
      cout << "Derived Class print_it" << endl; 
     } 
    }; 

    int main() { 

     DerivedClass dc; 
    } 

Hier ist der Ausgang:

BaseClass print_it 
Derived Class print_it 

I tried this code and the output is as stated above. Allerdings habe ich versucht, auch das gleiche Beispiel ohne das virtuelle Stichwort:

class BaseClass { 
    public: 
     BaseClass() { 
      print_it(); 
     } 
     void print_it() { 
      cout << "BaseClass print_it" << endl; 
     } 
    }; 

    class DerivedClass : public BaseClass { 
    public: 
     DerivedClass() { 
      print_it(); 
     } 
     void print_it() { 
      cout << "Derived Class print_it" << endl; 
     } 
    }; 

    int main() { 

     DerivedClass dc; 
    } 

and got the same result.

Worin besteht der Unterschied und wovor warnen sie?

@marked als Duplikat:

Diese Frage ist anders als die consturctors beide anstelle eines Konstruktor die virtuelle Methode aufrufen, die virtuelle Methode aufrufen.

+1

Die Gefahr ist: in Konstruktoren und Destruktoren sind virtuelle Funktionen nicht (virtuell das ist). –

+2

Nicht ganz korrekt. Sie sind virtuell, aber wenn ein Konstruktor ausgeführt wird, * ist dies eine Instanz der Klasse des laufenden Konstruktors und keine Instanz der Klasse, zu der sie letztendlich gehört. Also, welcher Konstruktor ausgeführt wird, kann überraschend sein. – gnasher729

+0

@ gnasher729 könntest du erklären, was ich erwarten sollte, weil ich dieses Ergebnis erwartet habe und die Gefahr nicht sehe. Nicht zu wissen, was andere erwarten, könnte zu Missverständnissen führen. –

Antwort

7

Es gibt keinen Unterschied. Das ist die Gefahr.

Wenn Sie es nicht besser wüsste, dann Sie diese stattdessen vielleicht erwarten:

Derived Class print_it 
Derived Class print_it 

Die Erwartung ist es, denn wenn man die virtualprint_it() von Funktionen in Base nennen, Polymorphismus bedeutet, dass Sie in der Regel die Derived bekommen Version stattdessen.

Aber, wenn Sie es im Base Konstruktor schreiben, der Base Teil des Objekts ist noch im Aufbau, und die „dynamische Art“ des Objekts im Bau ist noch Base, nicht Derived. Sie erhalten also nicht das übliche polymorphe Verhalten.

Der Artikel warnt Sie vor dieser Tatsache.

+0

Das wichtige Ding ist "Konstruktion des abgeleiteten Teils des Objekts hat noch nicht begonnen" (wenn) nicht "ein Funktionsaufruf im Basiskonstruktor geschrieben" (wo) . Wenn Sie schreiben: Base :: Base() {Base :: nonvirt(); } void Basis :: nonvirt() {this-> virt(); } 'dies wird auch erreichen' Base :: virt() 'und ein späterer Aufruf von' nonvirt() 'nach Abschluss der Konstruktion wird' Derived :: virt() 'erreichen. –