Scott Meyer
在他的书Effective C++
中说,dynamic_cast
用于执行向下或跨越继承层次结构的安全转换。也就是说,您使用dynamic_cast将对基类对象的指针或引用转换为对派生或同级基类对象的指针或引用,以便您可以确定转换是否成功。
失败的转换由空指针(当转换指针时)或异常(当转换引用时)指示。
我想得到两个代码片段,显示在可以指示转换指针和转换引用的情况下失败的转换。
对于指针,这是一个简单的空检查:
A* a = new A();
B* b = dynamic_cast<B*>(a);
if (b == nullptr)
{
// Cast failed
}
作为参考,你可以抓住:
try {
SomeType &item = dynamic_cast<SomeType&>(obj);
}
catch(const std::bad_cast& e) {
// Cast failed
}
根据OP的评论(“我不明白斯科特提到的强制转换如何会失败。”),这里真正的问题实际上是:“
dynamic_cast
怎么会失败?”
失败的时间是当目标类型与对象的动态类型不匹配时。举个简单的例子:
struct A {
virtual ~A() {}
};
class B : public A {};
int main() {
A *a = new A;
B *b = dynamic_cast<B *>(a); // should fail
if (b == NULL)
std::cout << "First cast failed.\n";
A *c = new B;
b = dynamic_cast<B *>(c); // should succeed
if (b == NULL)
std::cout << "Second cast failed.\n";
return 0;
}
这里虽然
a
可以指向B
类型的对象,但它实际上确实指向A
类型的对象。当我们尝试进行动态转换以使其指向 B
时,会失败。在第二次尝试中,我们再次得到一个指针,它不仅可以而且确实指向B
类型的对象。既然如此,在这种情况下,dynamic_cast 到 B *
就会成功。
参考案例的基本情况没有(太大)改变,只是
a
、b
和 c
成为引用而不是指针,并且我们通过捕获异常来记录失败(@ReedCopsey 已经证明了这一点)很好,我认为我没有什么新的东西要添加)。
这是一个完整的示例,展示了
dynamic_cast
如何无法生成指针。
class A
{
public:
virtual void Foo();
};
class B: public A
{
};
class C: public A
{
};
void test()
{
A a;
B b;
A* pA = &b;
B* pB = dynamic_cast<B*>(pA); // this works OK, returns the expected pointer
C* pC = dynamic_cast<C*>(pA); // this returns NULL because B isn't a C
}
在现实世界中,您将尝试投射并非如此直接创建的指针,例如它们可能来自
vector
。