Даустаун в алмазной иерархии
Почему static_cast
не может отключиться от виртуальной базы?
struct A {};
struct B : public virtual A {};
struct C : public virtual A {};
struct D : public B, public C {};
int main()
{
D d;
A& a = d;
D* p = static_cast<D*>(&a); //error
}
g++ 4.5 говорит:
error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’
Решение состоит в использовании dynamic_cast
? но почему. Что такое рациональное?
- изменить -
Очень хорошие ответы ниже. В ответах подробно не указано, каким образом субобъекты и vtables могут быть заказаны. Следующая статья дает хорошие примеры для gcc:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting
Ответы
Ответ 1
Потому что, если объект действительно имеет тип E
(полученный из D), расположение субобъекта A
относительно подобъекта D
может быть иным, чем если объект фактически D
.
На самом деле это происходит, если вы считаете, что вместо кастования от A до C. Когда вы выделяете C, он должен содержать экземпляр A и он живет с некоторым определенным смещением. Но когда вы назначаете D, подобъект C ссылается на экземпляр A, который поставляется с B, поэтому смещение отличается.
Ответ 2
Очевидным ответом является то, что стандарт говорит так.
мотивация в этом стандарте заключается в том, что static_cast
должен быть близок к тривиальному, самое большее, простое дополнение или
вычитание константы в указатель. Где спустит
для виртуальной базы потребуется более сложный код: возможно,
даже с дополнительной записью в vtable где-нибудь. (Это
требует нечто большее, чем константы, поскольку положение
D
относительно A
может измениться, если есть дальнейший вывод.)
Преобразование очевидно выполнимо, поскольку, когда вы звоните
виртуальная функция на A*
, и функция реализована
в D
, компилятор должен это сделать, но дополнительные служебные данные были
считается неуместным для static_cast
. (Предположительно,
единственной причиной использования static_cast
в таких случаях является
оптимизации, поскольку dynamic_cast
обычно является предпочтительным
решение. Поэтому, когда static_cast
, вероятно, будет таким же дорогим, как
dynamic_cast
в любом случае, зачем его поддерживать.)