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

How to identify failed casts using dynamic_cast operator?

本文关键字:失败 转换 识别 运算符 何使用 dynamic cast      更新时间:2023-10-16

Scott Meyer在其著作《Effective C++》中表示,dynamic_cast用于执行向下或跨继承层次结构的安全强制转换。也就是说,使用dynamic_cast将基类对象的指针或引用强制转换为派生基类对象或同级基类对象的指向或引用,这样就可以确定强制转换是否成功。

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

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

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

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
}

根据OP的评论("我不明白Scott提到的强制转换怎么会失败。"),这里真正的问题实际上是:"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类型的对象。当我们尝试执行dynamic_cast以使其指向B时,会失败。在第二次尝试中,我们再次获得一个指针,该指针不仅可以,而且可以指向类型为B的对象。既然如此,那么在这种情况下,对B *的dynamic_cast就成功了。

引用情况下的基本情况没有太大变化,只是abc变成了引用而不是指针,我们通过捕获异常来注意到失败(@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