2012-06-17 20 views
37

załóżmy ten scenariusz w Visual C++ 2010:Zastępowanie metody non-wirtualne

#include <iostream> 
#include <conio.h> 

using namespace std; 

class Base 
{ 
public: 
    int b; 
    void Display() 
    { 
     cout<<"Base: Non-virtual display."<<endl; 
    }; 
    virtual void vDisplay() 
    { 
     cout<<"Base: Virtual display."<<endl; 
    }; 
}; 

class Derived : public Base 
{ 
public: 
    int d; 
    void Display() 
    { 
     cout<<"Derived: Non-virtual display."<<endl; 
    }; 
    virtual void vDisplay() 
    { 
     cout<<"Derived: Virtual display."<<endl; 
    }; 
}; 

int main() 
{ 
    Base ba; 
    Derived de; 

    ba.Display(); 
    ba.vDisplay(); 
    de.Display(); 
    de.vDisplay(); 

    _getch(); 
    return 0; 
}; 

Teoretycznie wyjście z tej małej aplikacji powinno być:

  • fundamentowe: Non-wirtualny wyświetlacz.
  • Podstawa: wirtualny wyświetlacz.
  • Podstawa: Wyświetlanie inne niż wirtualne.
  • Wyprowadzony: Wyświetlanie wirtualne.

ponieważ metoda wyświetlania klasy Base nie jest metodą wirtualną, więc klasa pochodna nie powinna mieć możliwości jej przesłonięcia. Dobrze?

Problem polega na tym, że po uruchomieniu aplikacji, drukuje to:

  • Base: dla wirtualnego monitora.
  • Podstawa: wirtualny wyświetlacz.
  • Wyprowadzenie: Wyświetlanie inne niż wirtualne.
  • Wyprowadzony: Wyświetlanie wirtualne.

Tak więc albo nie rozumiem pojęcia metod wirtualnych, albo coś dziwnego dzieje się w Visual C++.

Czy ktoś może mi pomóc z wyjaśnieniem?

+0

absolutnie masz __Base: Non-virtual display .__ przy zmianie linii na 'de.Base :: Display()'. –

Odpowiedz

50

Tak, trochę nie rozumiesz.

Metoda o tej samej nazwie w klasie pochodnej ukryje w tym przypadku metodę nadrzędną. Można by sobie wyobrazić, że gdyby tak nie było, próba stworzenia metody o tej samej nazwie, co metoda nie-wirtualna klasy podstawowej, powinna spowodować błąd. Jest to dozwolone i nie stanowi to problemu - a jeśli wywołasz metodę bezpośrednio, tak jak to zrobisz, zostanie to nazwane dobrze.

Ale jako nie-wirtualne mechanizmy wyszukiwania metod C++, które pozwalają na polimorfizm, nie będą używane. Na przykład, jeśli stworzyłeś instancję swojej klasy pochodnej, ale wywołałeś swoją metodę "Display" przez wskaźnik do klasy bazowej, metoda bazy zostanie wywołana, podczas gdy dla "vDisplay" wywołana zostanie metoda pochodna.

Na przykład, spróbuj dodać te linie:

Base *b = &ba; 
b->Display(); 
b->vDisplay(); 
b = &de; 
b->Display(); 
b->vDisplay(); 

... i obserwować wyjście zgodnie z oczekiwaniami:

Podstawa: Non-wirtualny wyświetlacz.
Podstawa: wirtualny wyświetlacz.
Podstawa: Wyświetlanie inne niż wirtualne.
Wyprowadzenie: Wyświetlanie wirtualne.

+0

Witam @ sje397, dziękuję za odpowiedź. Czy możesz napisać przykład wywołania metody, jak powiedziałeś, poprzez wskaźnik do klasy bazowej? Dziękujemy! –

+0

@Lif Lazar: gotowe. – sje397

+0

Tak jak powiedziałem, możesz również połączyć się z (nie-wirtualną) metodą bazową z instancji pochodnej, używając składni rozdzielczości zakresu. –

3

Tak masz źle trochę:

Czyste funkcje wirtualne:

virtual void fun1()=0 -> musi być nadpisane w klasie pochodnej

wirtualne funkcje:

virtual void fun2() -> można przesłonić

Normalne funkcje:

void fun3() -> nie nadpisać

W celu uzyskania wykonania polimorfizm trzeba zastąpić funkcje wirtualne w C++

0

myślę, że może to być również lepiej spojrzeć na w kontekście wiązania statycznego i dynamicznego.

Jeśli metoda jest nie-wirtualna (jest już domyślnie w C++ w przeciwieństwie do Java), to metoda wiąże się z nią w czasie kompilacji, co uniemożliwia poznanie rzeczywistego obiektu, który zostanie wskazany w środowisku wykonawczym. Tak więc zmienny typ ma znaczenie "podstawową".