2011-12-27 26 views
7

Czy konieczne jest posiadanie definicji funkcji wirtualnej?Czy funkcja wirtualna ma zasadniczo definicję?

Rozważmy ten program poniżej próbka:

#include <iostream> 

using namespace std; 

class base 
{ 
    public: 
     void virtual virtualfunc(); 
}; 

class derived : public base 
{ 
    public: 
    void virtualfunc() 
    { 
     cout << "vf in derived class\n"; 
    } 
}; 

int main() 
{ 
    derived d; 
    return 0; 
} 

To daje link-błąd:

In function base::base() :: undefined reference to vtable for base

nie mam definicji dla funkcji wirtualnych w klasie bazowej. Dlaczego ten błąd występuje, mimo że nie wywołałem jawnie funkcji wirtualnej?

Interesującą rzeczą, którą odkryłem jest to, że jeśli nie stawiam obiektu klasy derived, błąd łącza już tam nie występuje. Dlaczego to? Co ma inicjacja z powyższym błędem linku?

+1

Ponowna edycja: jeśli nie tworzysz instancji "pochodnej" lub "bazy", dlaczego linker musi robić cokolwiek z jakąkolwiek metodą z tych dwóch klas? Jeśli klasy nie są przywoływane, linker nie ma powodu, aby próbować wyszukać je w plikach obiektowych. (Chyba, że ​​budujesz bibliotekę.) – Mat

+0

@Mat: Zgadzam się :) –

Odpowiedz

10

ISO C++ Określono, że wszystkie metody wirtualne klasy, które nie są czyste wirtualne musi być zdefiniowana.

referencyjny:

C++ 03 standardowe: 10.3 Funkcje wirtualne [class.virtual]

A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2).

Więc albo powinien uczynić funkcja czysto wirtualne lub przedstawić definicję dla niego.

Jeśli używasz gcc, możesz otrzymać dziwne błędy, jeśli nie zastosujesz się do tej standardowej specyfikacji. W gcc faq doccuments nim również:

The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined, but does not require any diagnostic for violations of this rule [class.virtual]/8 . Based on this assumption, GCC will only emit the implicitly defined constructors, the assignment operator, the destructor and the virtual table of a class in the translation unit that defines its first such non-inline method.

Therefore, if you fail to define this particular method, the linker may complain about the lack of definitions for apparently unrelated symbols. Unfortunately, in order to improve this error message, it might be necessary to change the linker, and this can't always be done.

The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7 .

+0

Świetnie !. Doskonale :) –

3

Musisz podać definicję lub oznaczyć ją jako abstrakcyjną/czysto-witualną.

void virtual virtualfunc() = 0; 
+0

Zwięzłe i prawie wszystko mówi. – Gravity

8

Trzeba zapewnić realizację funkcji wirtualnych (z jego zachowanie domyślne), chyba że zdefiniować funkcję być „czysty wirtualny”.

Więc Przykładem może być:

class base 
{ 
    public: 
     void virtual virtualfunc() {} //intentionally do nothing; 
}; 

lub

class base 
{ 
    public: 
     void virtual virtualfunc()=0; //pure virtual; 
}; 
0

Tak będzie trzeba ciało, ale być może to, co masz na myśli nazywany jest czyste funkcje wirtualne, które nie musiałyby definicja w klasie bazowej.

Składnia określenia te są następujące:

void virtual virtualfunc() = 0; 
1

W odpowiedzi błędu o vtable: Komenda wirtualnych w tym przypadku mówi, C++, aby produkować wirtualną tablicę metod w klasie bazowej. W ten sposób podczas korzystania z polimorfizmu, C++ jest w stanie zastąpić metody wirtualne klasy podstawowej metodami z klasy pochodnej o tej samej nazwie w czasie wykonywania. Ten błąd informuje użytkownika, że ​​wymiana nie jest możliwa. Aby naprawić ten błąd, musisz albo zaimplementować metodę, albo ustawić ją jako czystą wirtualną, dodając "= 0" na końcu definicji.

W odpowiedzi na zmiany: Przyczyną braku błędu podczas tworzenia obiektu jako klasy bazowej jest to, że klasa podstawowa nie musi uzyskiwać dostępu do tabeli wirtualnej. Z drugiej strony, jeśli faktycznie spróbujesz użyć tej metody, powinieneś otrzymać błąd, ponieważ nie istnieje żadna implementacja. Innymi słowy, nawet jeśli możesz utworzyć obiekt klasy bazowej, nie jest to pełna klasa.

+1

To jest głęboki powód !! – selfboot

Powiązane problemy