Dynamic Cast работает с несвязанными типами - PullRequest
9 голосов
/ 11 октября 2010
#include <iostream> 
using namespace std; 
class X{ 
     public: 
     virtual void f(){} 
}; 

class Y { 
     public: 
     virtual void g() {} 
}; 

int main() 
{ 
     X * x = new X(); 
     Y* y = dynamic_cast<Y*>(x); //A 
     // Y* y = static_cast<Y*>(x);  //B 
     cout << y << endl; 
} 

A компилируется, а B нет.Я понимаю, почему B не компилируется, но почему A компилируется, хотя X и Y - совершенно не связанные типы?

Ответы [ 7 ]

22 голосов
/ 11 октября 2010

Именно поэтому dynamic_cast допускается между несвязанными типами:

class X{ 
     public: 
     virtual void f(){} 
}; 

class Y { 
     public: 
     virtual void g() {} 
};

class Z : public X, public Y {};

int main()
{ 
     X* x = new Z(); 
     Y* y = dynamic_cast<Y*>(x); // compiles and yields non-null pointer
} 
5 голосов
/ 11 октября 2010

Динамическое приведение использует информацию о типе среды выполнения. Так что это допустимо в этом случае, но он вернет нулевой указатель. Статическое приведение оценивается компилятором.

1 голос
/ 11 октября 2010

Существует огромная разница между static_cast и dynamic_cast, я просто сведу обсуждение к миру объектов.

A static_cast может быть использовано для (печально известного) приведения,То есть:

void foo(Base& b) { Derived& d = static_cast<Derived&>(b); }

Компилятор может оценить, является ли это законным или нет, поскольку, имея определение Derived, он знает , является ли Derived на самом деле потомкомBase.

Для нетривиальных иерархий:

struct Base {};
struct D1: Base {};
struct D2: Base {};
struct Derived: D1, D2 {};

Это приведет к ошибке: компилятор не будет знать, с какой из баз (одна из D1 илиодин из D2, из которого вы пришли).

Или, если вы использовали virtual наследование:

struct VDerived: virtual VBase {};

, компилятору потребуется информация времени выполнения, и, следовательно, компиляция тоже не удалась.

A dynamic_cast однако гораздо умнее, хотя это происходит за счет накладных расходов времени выполнения.Компилятор генерирует информацию об объектах, обычно известных как RTTI (информация о типе RunTime), которую dynamic_cast будет исследовать, чтобы разрешить:

Cast в зависимости от истинного типа времени выполнения:

// will throw `bad_cast` if b is not a `Derived`
void foo(Base& b) { Derived& d = dynamic_cast<Derived&>(b); }

Приведение через ветви:

struct X {};
struct Y {};

void foo(X* x) { Y* y = dynamic_cast<Y*>(x); }

// If I add:
struct Z: X, Y {};

// then if x is in fact a Z, y will be non-null

Приведение, когда задействовано виртуальное наследование.

void bar(VBase* vb) { VDerived* vd = dynamic_cast<VDerived*>(vb); }

Приведение к void* для получения истинного адреса объекта (это несколько особенное).

void foobar(X* x)
{
   void* xAddr = dynamic_cast<void*>(x);

   Y* y = dynamic_cast<Y*>(y);
   void* yAddr = dynamic_cast<void*>(y);

   Z* z = dynamic_cast<Z*>(x);
   void* zAddr = dynamic_cast<void*>(z);
   if (z) { assert(xAddr == yAddr && xAddr == zAddr); }
}

Обратите внимание, что это по-прежнему не работает, если существует неоднозначность из-за иерархии (как в примере D1 / D2 выше).

1 голос
/ 11 октября 2010

Если [с помощью динамического приведения] вы пытаетесь привести к типу указателя, и этот тип не является фактическим типом объекта аргумента, то результатом приведения будет NULL .

Y* y = dynamic_cast<Y*>(x); // NULL because `X` is not a `Y`
1 голос
/ 11 октября 2010

динамическое приведение возвращает NULL, если оно не может выполнить приведение:

http://www.cplusplus.com/doc/tutorial/typecasting/

и поиск dynamic_cast

1 голос
/ 11 октября 2010

dynamic_cast выполняет проверку типа во время выполнения, используя RTTI, в то время как static_cast выполняет ее во время компиляции.То, что вы получили бы, если бы вы запустили A, было бы y == NULL.

Я предлагаю вам прочитать при приведении типа C ++.

1 голос
/ 11 октября 2010

Компилятору все равно, потому что это dynamic_cast. y будет NULL после приведения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...