2009-09-05 14 views
10

Aktualizacja: Zastąpiono przykład destruktora przykładem wywołania metody "prosto w górę".Pytania dotyczące dziedziczenia i V + C++

Cześć,

Jeśli mam następujący kod:

class a 
{ 
public: 
    virtual void func0(); // a has a VTable now 
    void func1(); 
}; 
class b : public a 
{ 
public: 
    void func0() { a::func0(); } 
    void func2(); 
}; 
  1. Czy tam vtable w B? B nie ma funkcji wirtualnych, ale wywołuje funkcję :: func0() z b :: func0()
  2. Czy func1 znajduje się w VTable? To nie jest wirtualne.
  3. Czy func2 znajduje się w VTable?
  4. Czy odpowiedzi na powyższe będą inne, jeśli nie było wywołania funkcji :: func0() w b :: func0()?

Dzięki

+5

Byłbym miło, gdybyś powiedział w takich pytaniach, z jakiego kompilatora korzystasz. Wirtualne tabele są specyficzne dla implementacji, chociaż podejmowane są starania o standaryzację ich formatu. –

+2

'b :: func0' ** jest ** wirtualny –

Odpowiedz

19

Jeśli zadeklarujesz funkcje wirtualne, powinieneś również zadeklarować swój destruktor wirtualny ;-).

  1. B ma stół wirtualnej, ponieważ ma funkcję, a mianowicie func0() wirtualnego. Jeśli deklarujesz funkcję (włącznie z destruktorem) wirtualną w klasie bazowej, wszystkie jej klasy pochodne będą miały funkcję z tym samym sygnaturą wirtualną. I spowoduje to, że będą mieć vtable. Co więcej, B miałby vtable nawet jeśli nie zadeklarowałeś w nim jawnie func0.

  2. Funkcje inne niż wirtualne nie są przywoływane przez vtables.

  3. Zobacz vtables 2.

  4. Nr klas są tworzone na podstawie deklaracji klasy. Ciała funkcji klasowych (nie mówiąc już o innych funkcjach) nie są brane pod uwagę. Dlatego B ma vtable, ponieważ jego funkcja func0() jest wirtualna.

Istnieje również skomplikowane szczegóły, choć nie jest to sedno Twojego pytania. Zadeklarowałeś swoją funkcję B::func0() jako wbudowaną. W kompilatorze gcc, jeśli funkcja wirtualna jest zadeklarowana jako wbudowana, zachowuje ona swój slot w wirtualnej tabeli, a szczelina wskazuje na funkcję specjalną emitowaną dla tej wbudowanej (która jest liczona jako przyjęcie jej adresu, co powoduje, że wbudowany emituje). Oznacza to, że funkcja inline nie wpływa na ilość slotów w tabeli i jej konieczność dla klasy.

+0

Zaktualizowano. Ponadto, jeśli więc funkcja jest deklarowana jako wirtualna w * dowolnej * klasie bazowej w hierarchii dziedziczenia, to ta funkcja jest wirtualna, nawet jeśli bezpośrednia klasa podstawowa (poziom 1 powyżej) nie oznacza jej jako wirtualnej? – jameszhao00

+0

Niezwykła odpowiedź. Powinien być zaakceptowany. +1 ode mnie. –

+0

@ jameszhao00: również zaktualizował odpowiedź. Masz rację: jeśli jakakolwiek pośrednia klasa bazowa (tj. Rodzic jakiegoś rodzica jakiegoś rodzica ... obecnej klasy) deklaruje funkcję wirtualną, to jest również wirtualna w bieżącej klasie. Zwróć uwagę, że przeciążone funkcje (void f (int) w porównaniu do void f (double)) są traktowane jako różne funkcje. –

5
  1. Tak, ponieważ jej klasa bazowa ma jedną; także jego destruktor jest wirtualny (nawet jeśli nie zadeklarowałeś go jako wirtualny), ponieważ destruktor klasy bazowej jest wirtualny.

  2. Nie

  3. nr

  4. nr Właściwie nie sądzę aktualny kod jest legalne: kompilator wywołać destruktor po wywołuje destruktor B, nawet jeśli don” t jawnie wywołać ~ A z ~ B; więc nie sądzę, że powinieneś wywołać ~ A z ~ B, nawet jeśli pozwala na to kompilator.

+0

Przepraszamy. Nie powinienem był używać destruktorów jako przykładu. Zaktualizowano. – jameszhao00

3

Odnosząc się do zaktualizowanego przykład:

  1. Tak, b ma vtable. Zauważ, że b :: func0() jest wirtualne (przesłania a :: func0()), nawet jeśli nie nazwałeś go jawnie jako wirtualny. Dziwna C++ "luka", jak sądzę.
  2. Nie. Funkcje inne niż wirtualne nie znajdują się w tabeli vtable.
  3. Zobacz 2.
  4. Nie. Przesłano: a func0(); nie ma znaczenia, czy wywołasz funkcję :: func0() czy nie.

kilka dodatkowych notach (kompilator zależne, ale są one dość powszechne uogólnienia):

  • Każda instancja b będzie miał wskaźnik do vtable, bo jesteś pochodzi z klasy który ma funkcje wirtualne.
  • To by było w przypadku , nawet jeśli nie zdefiniowałeś b :: func0().
  • W tej sytuacji, kompilator może mieć wystąpień b punktu do statyczny vtable „s, lub może utworzyć statyczną vtable dla b i wypełnić go z wskazówki do wskazówki do członków .
  • Ale to wciąż wymagane, tak aby można było prawidłowo dostęp instancję b poprzez wskaźnik do .
1
  • Jeśli funkcja klasa bazowa jest wirtualny wtedy jeśli przesłonić tej funkcji w klasie pochodnej jest niejawnie wirtualny nawet jeśli nie określają jednoznacznie. Jeśli klasa ma funkcję wirtualną, wówczas ma tabelę v.
  • tylko wirtualne funkcje obecne w vtable, Function1 nie będą przebywać w vtable
  • function2 nie będą przebywać w vtable samego powodu powyżej
  • Stworzenie vtable nie zależy od tego, czy wywołanie tej funkcji z klasy bazowej lub z innego . Wywołanie funkcji nie decyduje o tworzeniu vtable.
Powiązane problemy