2010-07-21 5 views
7

Ich las Google C++ Style Guide, und wurde in der Doing Work in Constructors Teil verwirrt. Einer der Nachteile der schweren Arbeit im Konstruktor zu tun ist:Zweifel in einem Nachteil der Arbeit in Konstruktoren

Wenn die Arbeit virtuelle Funktionen aufruft, diese Anrufe werden nicht die Unterklasse Implementierungen geschickt bekommen. Future Änderung an Ihrer Klasse kann ruhig dieses Problem einführen, auch wenn Ihre Klasse derzeit nicht unterklassifiziert ist, verursacht viel Verwirrung.

Ich habe nicht verstanden, was es bedeutet. Könnte jemand eine Erklärung liefern und warum dies als Nachteil angesehen werden kann?

+2

Dies ist einer der Gründe, warum ich den Google C++ Style Guide nicht mag. Der Aufruf virtueller Methoden aus Konstruktoren und Destruktoren sollte per se als Faustregel vermieden werden - wo Vermeiden ist nur dann, wenn Sie einen guten Grund haben und es in einer Code-Überprüfung verteidigen können. Auf der anderen Seite ist die Empfehlung, eine zweistufige Initialisierung zu verwenden, (schlichtweg falsch), und viele andere Styleguides empfehlen gegen zwei Schritte Initialisierung ... –

+2

Bedenke, dass Googles Styleguide trotz des Seitentitels für C++ ist . Sie verbieten Ausnahmen und geben eine Bastard-Sprache, in der viele C++ - Idiome entweder nicht verwendet werden können oder ihre Nützlichkeit beraubt sind. Dies ist der Grund, warum sie eine zweistufige Initialisierung und alle fehleranfälligen Kopfschmerzen erfordern; Es gibt keine Möglichkeit, Fehler von einem Konstruktor anzuzeigen. Wenn Sie keinen bestimmten Grund haben, dem Google-Stil zu folgen, ignorieren Sie ihn. –

Antwort

9

ich krass bin zerreißt einige Beispiel-Code aus der Wikipedia Virtual function Seite aus:

#include <iostream> 
#include <vector> 

class Animal { 
    public: 
     virtual void eat() const { 
      std::cout << "I eat like a generic Animal." << std::endl; 
     } 
     virtual ~Animal() { 
     } 
}; 

class Wolf : public Animal { 
    public: 
     void eat() const { 
      std::cout << "I eat like a wolf!" << std::endl; 
     } 
}; 

class Fish : public Animal { 
    public: 
     void eat() const { 
      std::cout << "I eat like a fish!" << std::endl; 
     } 
}; 

Wenn Sie eat() innerhalb des Animal Konstruktor aufrufen, nennen es die Animaleat() Funktion jedes Mal. Auch wenn Sie ein Objekt Wolf oder Fish erstellen, da der Animal-Konstruktor abgeschlossen wird, bevor das Unterklassenobjekt initialisiert wird, sind die überschreibenden eat-Funktionen noch nicht vorhanden.

Dies ist ein Nachteil, weil es Verwirrung zwischen dem was erwartet wird und was tatsächlich passiert, verursachen kann. Wenn ich eat überschreibe und dann ein Objekt meiner Unterklasse erzeuge, erwarte ich, dass meine überschriebene Funktion auch von einer Animal Referenz aufgerufen wird. Ich erwarte es, weil das passiert, wenn der Aufruf explizit durch Code außerhalb des Konstruktors erfolgt. Das Verhalten ist innerhalb des Konstruktors anders, was dazu führt, dass ich verwirrt den Kopf kratze.

+8

Keine Klasse Eidechse? –

+2

@Justin: Ich kann nicht glauben * Ich habe diese Gelegenheit verpasst. ;) –

4

Wenn ein Objekt erstellt wird, werden die Konstruktoren für Basisklassen zuerst aufgerufen. Da die abgeleitete Klasse noch nicht initialisiert wurde, wird für alle Aufrufe von virtuellen Methoden während des Basisklassenkonstruktors kein abgeleitetes Klassenobjekt zur Bearbeitung benötigt.

0

Die Aufgabe des Konstruktors besteht einfach darin, den Anfangszustand Ihres Objekts zu initialisieren. Wenn Sie Aufgaben ausführen, die auf Aktionen basieren, die in virtuellen Funktionen ausgeführt werden, können Sie einige unerwartete Ergebnisse erhalten, wenn Unterklassen mit der Implementierung dieser Funktionen beginnen.

1

Wenn Sie von der Klasse erben, werden die Methoden, die Sie überschreiben/implementieren, in diesem Fall nicht aufgerufen. Wenn also Employee im Konstruktor work() aufruft, werden Sie später mit Hourly :: work() und SalariedEmployee :: work() arbeiten, die nicht aufgerufen werden. Obwohl sie unterschiedliche Implementierungen haben, werden sie immer noch als Employee und nicht als ihre speziellen Implementierungen behandelt.

2

Wenn eine Instanz einer Unterklasse erstellt wird, wird zuerst der Konstruktor der Basisklasse und dann der Konstruktor der Unterklasse aufgerufen.

Wenn der Basisklassenkonstruktor eine virtuelle Methode aufruft, wird die Methode der Basisklasse anstelle der Unterklasse aufgerufen, obwohl die Instanz die einer Unterklasse ist. Dies könnte ein Problem sein.

Viel mehr Informationen hier: http://www.artima.com/cppsource/nevercall.html

0

Das Verhalten, das virtuelle Funktionsaufrufe nicht virtuell sind, ist gut definiert, aber sehr überraschend, so dass Compiler normalerweise Warnungen ausgeben.