2009-08-14 13 views
16

W języku C++, jaki jest narzut (pamięć/procesor) związany z dziedziczeniem klasy bazowej, która nie ma funkcji wirtualnych? Czy jest tak dobry jak zwykła kopia + pasta członków klasy?Obciążenie dziedziczeniem C++ bez funkcji wirtualnych

class a 
{ 
public: 
    void get(); 
protected: 
    int _px; 
} 

class b : public a 
{ 

} 

porównaniu z

class a 
{ 
public: 
    void get(); 
protected: 
    int _px; 
} 

class b 
{ 
public: 
    void get(); 
protected: 
    int _px; 

} 
+5

Jaki jest sens używania dziedziczenia (publicznego), jeśli nie masz funkcji wirtualnych? Będziesz potrzebował co najmniej wirtualnego destruktora. –

+8

@Neil może być do ponownego użycia kodu, unikając ponownego odkrywania koła – vehomzzz

+5

W takim przypadku powinien używać kompozycji, prywatnego dziedziczenia lub wolnych funkcji. –

Odpowiedz

23

Może a będzie niewielki narzut pamięci (ze względu na dopełnienie) podczas korzystania z dziedziczenia w porównaniu do kopiowania i przeszłości, należy rozważyć następujące definicje klasy:

struct A 
{ 
    int i; 
    char c1; 
}; 

struct B1 : A 
{ 
    char c2; 
}; 


struct B2 
{ 
    int i; 
    char c1; 
    char c2; 
}; 

sizeof (B1) będzie prawdopodobnie 12, podczas gdy sizeof (B2) może być po prostu 8. Wynika to z tego, że klasa podstawowa A zostaje dopełniona osobno do 8 bajtów, a następnie B1 zostaje dopełniona do 12 bajtów.

+0

Ah ładna obserwacja. – jameszhao00

+0

Wszystkie inne odpowiedzi są prawidłowe, ale jest to coś, o czym wcześniej nie wiedziałem/myślałem. – jameszhao00

1

nie bardzo, to tylko zwiększona pamięć przez klasę bazową. Możesz przeczytać więcej w here w C++ FAQ

+0

Mam świadomość, że po wprowadzeniu funkcji wirtualnych istnieje koszt funkcji tabeli. Zastanawiam się, jak kompilator C++ przetwarza dziedziczenie bez polimorfizmu. – jameszhao00

+0

po pierwsze, nie przydziela pamięci dla vtable, nie tworzy vpointera w klasie bazowej, więc zarówno kompilator, jak i środowisko wykonawcze zajmuje mniej niż z wirtualną funkcją/lekami. co próbujesz osiągnąć? – vehomzzz

14

Kompilacja zajmie nieco więcej czasu i nie będzie dodatkowego obciążenia środowiska wykonawczego. Z punktu widzenia optymalizatora metody inne niż wirtualne są takie same jak procedury - można je wywoływać tylko za pomocą adresu pamięci, bez obciążania z tabeli metod wirtualnych.

+0

Dlaczego kompilacja trwa dłużej? po prostu ciekawy. Myślałem, że kompilator jest teraz dość sprytny :) – vehomzzz

+6

Zwiększony czas będzie tylko kilka milisekund, ponieważ kompilator będzie musiał zbudować drzewo dziedziczenia. Nie warto się tym przejmować. –

+0

Nie masz na myśli "tego samego, co metody nie dziedziczone"? – einpoklum

3

Jeśli zapomnisz dziedziczenia wirtualnego, mając klasę podstawową jest równoważne, pamięć i wydajność, do posiadania członka tej samej klasy. Wyjątkiem jest to, że czasami może być jeszcze lepiej (na przykład pusta klasa ma rozmiar co najmniej jednego, ale posiadanie pustej klasy bazowej może często nie mieć narzutów).

2

Jeśli możesz mieć wskaźnik typu Base *, który wskazuje na obiekt typu Derived *, prawdopodobnie potrzebujesz wirtualnego destruktora, a twoje pierwotne założenie już nie obowiązuje. Jeśli klasa pochodna ma pusty destruktor i nie ma żadnych członków lub wszystkie są typu POD, można uciec bez wirtualnego destruktora, ale zazwyczaj lepiej jest go odtworzyć i uczynić wirtualnym od samego początku.

Kompilator wygeneruje bezpośrednie wywołanie kodu implementującego każdą nie wirtualną funkcję członkowską, w związku z czym nie będzie żadnych narzutów.

Powiązane problemy