Downcast в алмазной иерархии - PullRequest
23 голосов
/ 18 мая 2011

Почему 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
}  

г ++ 4,5 говорит:

 error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’

Решение заключается в использовании dynamic_cast? но почему. Что такое рациональное?

- редактировать -
Очень хорошие ответы ниже. Нет ответов, подробно описывающих, как субобъекты и таблицы могут быть упорядочены. Следующая статья дает несколько хороших примеров для gcc:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting

Ответы [ 2 ]

11 голосов
/ 18 мая 2011

Очевидный ответ: потому что так говорится в стандарте.Мотивом этого в стандарте является то, что static_cast должно быть близко к тривиальному - самое большее, простое сложение или вычитание константы для указателя.Где переход на виртуальную базу потребует более сложного кода: возможно, даже с дополнительной записью в виртуальной таблице.(Это требует чего-то большего, чем константы, поскольку позиция D относительно A может измениться, если произойдет дальнейшая деривация.) Преобразование очевидно выполнимо, поскольку при вызове виртуальной функции на A*функция реализована в D, компилятор должен это делать, но дополнительные издержки считались неуместными для static_cast.(Предположительно, единственной причиной для использования static_cast в таких случаях является оптимизация, поскольку dynamic_cast обычно является предпочтительным решением. Поэтому, когда static_cast, скорее всего, будет стоить столько же, сколько dynamic_cast, зачем его поддерживать?)1011 *

10 голосов
/ 18 мая 2011

Поскольку, если объект действительно имеет тип E (производный от D), местоположение подобъекта A относительно подобъекта D может отличаться от того, если объект на самом деле D.

На самом деле это уже происходит, если вы рассматриваете приведение вместо A к C. Когда вы выделяете C, он должен содержать экземпляр A, и он живет с некоторым определенным смещением. Но когда вы выделяете D, подобъект C ссылается на экземпляр A, поставляемый с B, поэтому его смещение отличается.

...