2013-07-28 14 views
5

więc niemożliwe jest przygnębiony użyciu static_cast z wirtualnego dziedziczenia, ale jak to jest możliwe, aby wykonać następujące czynności uskok:W jaki sposób można użyć static_cast w przypadku dziedziczenia wirtualnego?

class Base {...}; 
class Derived : public virtual Base {...}; 

... 

Derived *d = new Derived(); 
Base *b = static_cast<Base*>(d); 

układ pamięci obiektu:

[ derived part | base part ] 

wiem, że upcasting jest uważany "bezpieczny", ale w jaki sposób kompilator może znać przesunięcie do bazowego pod-obiektu podczas kompilacji, kiedy dziedziczenie jest wirtualne? Czy static_cast używają vtable?

Jest to szczególnie kłopotliwe, kiedy mamy coś takiego (zauważ, że to nie jest wirtualny):

class Third : public Derived {...}; 

... 

Derived *d = new Third();   // non-virtual upcast, no offset will be added 
Base *b = static_cast<Base*>(d); 

Tym razem użył tego samego static_cast linię, ale przesunięcie do sub-object Base jest inna!

układ pamięci obiektu:

[ derived part | third part | base part ] 

Więc jak można określić w czasie kompilacji, czy to zależy od rzeczywistego dynamicznego typu obiektu d punkty?

Odpowiedz

3

Kiedy masz wskaźnik do Derived w Twoim przypadku, to jest jasne, które Base ma być używany i można nawet niejawnie przekonwertować kursor do Derived do wskaźnika do Base! Jeśli potrzebna jest jakakolwiek zmiana adresu, kompilator wymyśli, jak to zrobić, używając wbudowanego wskaźnika, tabeli vtable lub czegoś podobnego: dokładne podejście nie jest zalecane przez standard C++. To, co zostało zrobione dokładnie, zależy od ABI. Na przykład dla Itanium C++ ABI wydaje się, że przesunięcia dla wirtualnych baz są przechowywane w tabelach wirtualnych.

+0

Zwykle tak jest z tego, co wiem, że przesunięcia są przechowywane w vtable. Jednak to nie odpowiada na pytanie, jak to zrobić statycznie podczas kompilacji. Jeśli przyjrzeć się dwóm dostarczonym przeze mnie przypadkom, pojawia się pytanie, który z nich ma odpowiednie przesunięcie? Którym powinien się przyglądać kompilator, vable programu Derived lub vtable Third? Oczywiście 2 przesunięcia w vtables są różne, a wybór odpowiedniego vtable zależy od typu run-s. Dlatego nie mogę zrozumieć, jak to jest zrobione statycznie. –

+0

"Statyczny" w 'static_cast' nie oznacza, że ​​jest on wykonywany podczas kompilacji! Oznacza to po prostu, że kompilator może statycznie ustalić, gdzie znaleźć informacje w czasie kompilacji: Na przykład, wie gdzie szukać offsetu w vtable lub gdzie znajduje się wbudowany wskaźnik do bazy (w zależności od tego, jak wirtualne dziedziczenie jest zaimplementowane). Nie będzie szukał dopasowania jakiejś klasy w vtable, jak robi to 'dynamic_cast'. –

+0

Mówisz, że static_cast ma jakiś aspekt dynamiczny, widzę. Według tej logiki, dlaczego static_cast nie może powodować downcastingu w dziedziczeniu wirtualnym? –

Powiązane problemy