#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
是完全不相关的类型?
答案 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)
答案 5 :(得分:1)
如果[通过使用动态强制转换]尝试强制转换为指针类型,并且该类型不是参数对象的实际类型,则强制转换的结果将为 NULL 。< / p>
Y* y = dynamic_cast<Y*>(x); // NULL because `X` is not a `Y`
答案 6 :(得分:1)
static_cast
和dynamic_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
示例),这仍然无效。