动态Cast用于不相关的类型

时间:2010-10-11 15:06:28

标签: c++ inheritance

#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会被编译,尽管XY是完全不相关的类型?

7 个答案:

答案 0 :(得分:22)

这就是为什么在不相关的类型之间允许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
} 

答案 1 :(得分:5)

动态强制转换使用运行时类型信息。所以这是合法的做这种情况但它会返回一个空指针。 静态强制转换由编译器评估。

答案 2 :(得分:1)

编译器不关心,因为它是dynamic_cast。演员之后y将是NULL

答案 3 :(得分:1)

dynamic_cast使用RTTI在运行时执行类型检查,而static_cast在编译时执行它。因此,如果您运行A,您将获得y == NULL

我建议您使用read up进行C ++类型转换。

答案 4 :(得分:1)

如果动态转换无法完成转换,则返回NULL:

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

并搜索dynamic_cast

答案 5 :(得分:1)

如果[通过使用动态强制转换]尝试强制转换为指针类型,并且该类型不是参数对象的实际类型,则强制转换的结果将为 NULL 。< / p>

Y* y = dynamic_cast<Y*>(x); // NULL because `X` is not a `Y`

答案 6 :(得分:1)

static_castdynamic_cast之间存在巨大差异,我只会将讨论简化为对象世界。

static_cast可用于(臭名昭着)上传。那就是:

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

编译器可以评估这是否合法,因为Derived的定义知道 Derived是否实际上是{{1}的后代}。

对于非平凡的层次结构:

Base

这会产生错误:编译器不会知道哪个基数(来自struct Base {}; struct D1: Base {}; struct D2: Base {}; struct Derived: D1, D2 {}; 的基数或来自D1的基数)。

或者如果您使用D2继承:

virtual

编译器需要运行时信息,因此编译也会失败。

然而,struct VDerived: virtual VBase {}; 更加聪明,尽管这是以运行时开销为代价的。编译器生成有关通常称为RTTI(运行时类型信息)的对象的信息,dynamic_cast将探索允许:

根据真实的运行时类型进行强制转换:

dynamic_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示例),这仍然无效。