如何使用dynamic_cast运算符识别失败的强制转换?

时间:2012-07-16 18:17:31

标签: c++ pointers reference dynamic-cast

Scott Meyer在他的书Effective C++中说dynamic_cast用于执行安全转换或跨越继承层次结构。也就是说,使用dynamic_cast将指针或对基类对象的引用转换为指针或对派生或兄弟基类对象的引用,以便您可以确定转换是否成功。

失败的强制转换由空指针(在转换指针时)或异常(在转换引用时)指示。

我想得到两个代码片段,显示在投射指针的情况下失败的强制转换,并且可以指示投射引用。

3 个答案:

答案 0 :(得分:26)

对于指针,这是一个简单的空检查:

A* a = new A();
B* b = dynamic_cast<B*>(a);

if (b == NULL)
{
    // Cast failed
}

对于参考,你可以抓住:

try {
    SomeType &item = dynamic_cast<SomeType&>(obj);
}
catch(const std::bad_cast& e) {
    // Cast failed
}

答案 1 :(得分:4)

这是一个完整的示例,说明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

答案 2 :(得分:3)

基于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类型的对象,但实际上 指向{{1}类型的对象}。当我们尝试执行dynamic_cast以使其指向A时,会失败。在第二次尝试中,我们再次有一个指针,它不仅可以,而且指向B类型的对象。既然如此,那么B的dynamic_cast就会成功。

参考案例的基本情况不会发生太大变化,只有B *ab成为引用而不是指针,我们注意到失败了异常(@ReedCopsey已经很好地证明了我认为我没有新的东西可以添加)。