2013-07-28 3 views
5

Так что невозможно обратное приведение с помощью static_cast с виртуальным наследованием, но как можно сделать следующий вентиляционный:Как использовать static_cast с виртуальным наследованием?

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

... 

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

макет памяти объекта:

[ derived part | base part ] 

Я знаю, что приведение к базовому типу считается «безопасно», но как компилятор может узнать смещение базового под-объекта во время компиляции, когда наследование виртуально? Использует ли static_castvtable?

Это особенно сбивает с толку, когда мы что-то вроде этого (обратите внимание, что это не виртуальные):

class Third : public Derived {...}; 

... 

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

На этот раз я использовал ту же самую static_cast линию, но смещение к Base подъобекта отличается!

Разметка памяти объекта:

[ derived part | third part | base part ] 

Так как это может быть определено во время компиляции, если это зависит от фактического динамического типа объекта d указывает на?

ответ

3

Если у вас есть указатель на Derived в вашем случае, это ясно, какой Base будет использоваться, и вы можете даже неявно преобразовать указатель на Derived к указателю Base! Если требуется какая-либо корректировка адреса, компилятор будет определять, как это сделать, используя встроенный указатель, таблицу vtable или что-то еще: точный подход не предписывается стандартом C++. То, что делается точно, зависит от ABI. Например, для Itanium C++ ABI кажется, что смещения виртуальных баз хранятся в виртуальных таблицах.

+0

Это, как правило, из того, что я знаю, что смещения хранятся в таблице vtable. Однако это не отвечает на вопрос о том, как это делается статически во время компиляции. Если вы посмотрите на два случая, которые я предусмотрел, возникает вопрос, какой vtable имеет правильный сдвиг? На какой компилятор должен смотреть виртуальный стол Derived или vtable? Очевидно, что 2 смещения в vtables различны, и выбор правой таблицы vtable зависит от типа времени выполнения. Вот почему я не понимаю, как это делается статически. –

+0

«Статический» в 'static_cast' не означает, что это делается во время компиляции! Это просто означает, что компилятор может статически определять, где найти информацию во время компиляции: например, он знает, где искать смещение в таблице vtable или где находится встроенный указатель на базу (в зависимости от того, как виртуальное наследование реализуется). Он не будет искать соответствие некоторого класса в vtable, как 'dynamic_cast'. –

+0

Итак, вы говорите, что у static_cast есть динамический аспект, я вижу. По этой логике почему static_cast не может преуменьшать виртуальное наследование? –