2010-01-23 16 views
11

Kiedy czytam Effective C++, mówi, nigdy nie redefiniuj funkcji nie-wirtualnej w C++.przedefiniować funkcję inną niż wirtualna w C++

Jednak po przetestowaniu tego kodu poniższy kod kompiluje się poprawnie. Więc o co chodzi? To błąd, czy tylko zła praktyka?

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; 
} 

Odpowiedz

24

Przedefiniowanie funkcji innej niż wirtualna jest w porządku, o ile nie zależy to od zachowania wirtualnej wysyłki.

Autor książki obawia się, że przekażesz swoją B* funkcji, która ma A*, a następnie być zdenerwowany, gdy wynik jest wywołanie metody bazowej, a nie metoda pochodna.

+2

Urocza odpowiedź! Krótko mówiąc, i pokazuje, jak emocjonalne jest programowanie. – DarenW

+0

Nie zgadzam się, autor Scott Meyers wskazuje, że dziedziczenie publiczne ustanawia niezmienną specjalizację dla klasy b. Ponadto użycie klasy jest mylące, gdy zachowanie f() zależy od definicji wskaźnika, a nie od definicji obiektu. Przykład: B x; A * ptr = & x; ptr-> f() // wywołuje wersję f() klasy A, a nie wersję B klasy f(), która jest myląca. – TheChrisONeil

7

Spróbuj tego:

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

Myślę, że odpowiedź będzie oczywista raz zobaczyć wynik ;-).

Bez wirtualny mechanizm późnego wiązania nie będą wykorzystywane, stąd funkcja, która jest zdefiniowana dla tego typu wskaźnik będzie używany, nie późnej zbindowanych funkcja chcesz zadzwonić. Prowadzi to do wielu źle śledzonych błędów.

W związku z tym, co robisz, to tworzenie nowej funkcji. Może to być zamierzone, ale ktoś czytający twój kod może oczekiwać, że powyższy kod zadziała z późnym wiązaniem. Bardzo mylące.

Jedną z cech naprawdę chciałem zobaczyć to ostrzeżenie w takim przypadku o „przedefiniowanie” słowo kluczowe aby zapobiec, ale sny są marzenia, a rzeczywistość jest rzeczywistością -_-

2

Chodzi o to, jeśli na przykład masz listę wskaźników do klasy bazowej (List<A *> list), a następnie wywołasz f(), ponownie wdrożona metoda w B nie zostanie wywołana.

Powiązane problemy