2010-01-23 5 views
11

Wenn ich Effektives C++ lesen, heißt es, nie eine nicht-virtuelle Funktion in C++ neu definieren.eine nicht virtuelle Funktion in C++ neu definieren

Allerdings, wenn ich es getestet habe, kompiliert der folgende Code richtig. Also, was ist der Punkt? Es ist ein Fehler oder nur eine schlechte Übung?

class A { 

    public: 
    void f() { cout<<"a.f()"<<endl;}; 
}; 

class B: public A { 
    public: 
    void f() { cout<<"b.f()"<<endl;}; 
}; 


int main(){ 

    B *b = new B(); 
    b->f(); 
    return 0; 
} 

Antwort

24

Die Neudefinition einer nicht virtuellen Funktion ist in Ordnung, solange Sie nicht vom Verhalten des virtuellen Versands abhängig sind.

Der Autor des Buches hat Angst, dass Sie Ihre B* an eine Funktion übergeben, die eine A* dauert und dann verärgert sein, wenn das Ergebnis ein Aufruf der Basismethode ist, nicht die abgeleitete Methode.

+2

Schöne Antwort! Kurz, auf den Punkt, und zeigt, wie emotionale Programmierung ist. – DarenW

+0

Ich stimme nicht zu, der Autor Scott Meyers weist darauf hin, dass öffentliche Vererbung eine Invariante über Spezialisierung für Klasse b etabliert. Außerdem ist die Klassenverwendung verwirrend, wenn das Verhalten von f() von der Zeigerdefinition und nicht von der Objektdefinition abhängt. Beispiel: B x; A * ptr = & x; ptr-> f() // ruft die Klasse-A-Version von f() und nicht die Klasse-B-Version von f() auf und das ist verwirrend. – TheChrisONeil

7

Try this:

int main(){ 
    A *b = new B(); 
    b->f(); 
    return 0; 
} 

Ich denke, die Antwort auf der Hand sein wird, sobald Sie sehen das Ergebnis ;-).

Ohne den virtuellen Mechanismus zu verwenden, wird der späte Bindemechanismus nicht verwendet, daher wird die Funktion verwendet, die für diesen Zeigertyp definiert ist, und nicht die späte Funktion, die Sie aufrufen möchten. Dies führt zu Tonnen von schlecht verfolgbaren Fehlern.

Daher erstellen Sie eine neue Funktion. Es kann sein, was Sie beabsichtigten, aber jemand, der Ihren Code später liest, könnte erwarten, dass der obige Code mit späte Bindung funktioniert. Sehr verwirrend.

Eine der Funktionen, die ich wirklich sehen wollte eine Warnung in einem solchen Fall mit einer „Neudefinition“ Stichwort es zu verhindern, aber Träume sind Träume und Realität ist Realität -_-

2

Der Punkt ist, Wenn Sie beispielsweise eine Liste von Zeigern zur Basisklasse (List<A *> list) haben und dann f() aufrufen, wird die neu implementierte Methode in B nicht aufgerufen.

Verwandte Themen