2013-07-16 14 views
5

Jestem nowy w C++ i właśnie poznałem funkcje wirtualne.Zasada funkcji wirtualnych w C++

Słyszałem, że kompilator robi vtable, który zawiera funkcje wirtualnego adresu klasa jest, kiedy zdefiniować funkcję wirtualną. Kiedy wywoływana jest funkcja wirtualna, kompilator znajduje jej adres przy użyciu tabeli vtable.

naprawdę nie mogę zrozumieć, dlaczego kompilator nie wywołać funkcję instancji klasy, że obiekt należy.

Dlaczego kompilator korzysta z tabeli vtable? Czy możesz to wyjaśnić?

+0

Dlatego użycie vtable jest to, że gdy grupa pochodzi ponownie realizuje funkcję wirtualnego w konstruktora klasy pochodnej vtable jest aktualizowany, aby wskazać wykonania pochodzącego zamiast zasady. – Borgleader

+5

Dwa słowa: * dynamiczna wysyłka *. Mimo że poniżej znajdują się dobre wyjaśnienia, musisz przynajmniej usłyszeć poprawną terminologię. –

Odpowiedz

9

Nie mogę naprawdę zrozumieć, dlaczego kompilator nie nazwał funkcji instancji klasy?

To właśnie robi kompilator - zapewnia, że ​​twój program wywoła funkcję klasy, do której należy instancja. Kluczowym słowem jest tutaj instancja: znajomość klasy instancji nie jest dostępna w czasie kompilacji.

Rozważmy prosty przykład:

struct Dude { 
    virtual void howdy() = 0; 
}; 
struct Bob : public Dude { 
    virtual void howdy() { cout << "Hi, Bob!" << endl; } 
}; 
struct Moe : public Dude { 
    virtual void howdy() { cout << "Hi, Moe!" << endl; } 
}; 
// Note the pass by reference below: passing by reference or by pointer, 
// but not by value, is important for achieving polymorphic behavior. 
void say_hi(Dude& dude) { 
    dude.howdy(); // <<== Here is the tricky line 
} 
int main(int argc, char* argv[]) { 
    Bob b; 
    Moe m; 
    Dude *d = rand() & 1 ? (Dude*)&b : &m; 
    say_hi(*d); 
} 

Uwaga najtrudniejsza linia: kompilator ma instancji, ale nie wiem klasę. Właściwie to zna klasę, ale nie najbardziej konkretną. Wiedza, którą kompilator ma w czasie kompilacji, jest wystarczająca, aby wiedzieć, że istnieje funkcja o nazwie howdy, ale nie jest wystarczająca, aby zdecydować, która z kilku możliwości będzie tą, którą należy wywołać w środowisku wykonawczym.

To tutaj vtables przychodzi na ratunek: kompilator wie, że podklasy Dude będą miały wskaźnik do ich funkcji howdy osadzonej gdzieś w ich vtable. To wszystko, co muszą wiedzieć w czasie kompilacji! Wstawiają wywołanie wirtualne, które wyszukuje wskaźnik funkcji w czasie wykonywania, osiągając oczekiwane zachowanie (wymyślnym określeniem tego rodzaju zachowania jest "polimorfizm"). Oto demo of this program działający na idee.

+0

W rzeczywistości 'howdy' może być' const', a ty możesz przekazać 'const' odwołanie do' say_hi' ... ale ja po prostu dziurkuję. : P –

+1

@DanielKamilKozar Oczywiście, to właśnie robiłbym w problemach produkcyjnych. Jednak nie jest to niezbędne do zrozumienia podstawowych zasad polimorfizmu, więc usunąłem przykład do jego absolutnego minimum. – dasblinkenlight

+3

Twój przykład jest poprawny, ale może nie idealny: znam przynajmniej jeden kompilator, który rozwiąże połączenia podczas kompilacji. Bardziej klasyczny "Base * p; if (rand() i 1) p = new Derived1; else p = new Derived2; p-> do_something(); 'jest nieco lepszy, ponieważ unika tego" problemu "i, moim zdaniem, jest bardziej ilustracyjny. –

Powiązane problemy