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

nit*_*ian 13 c++ pointers dynamic-cast reference

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

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

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

Ree*_*sey 27

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

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

if (b == NULL)
{
    // Cast failed
}
Run Code Online (Sandbox Code Playgroud)

对于参考,您可以捕获:

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

  • @LinuxPenseur:`new()`在失败时不一定返回空指针,你可能还需要在这里检查一个异常.如果`a`不是'B`的实例,`b`将变为'NULL`. (2认同)

Jer*_*fin 6

根据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;
}
Run Code Online (Sandbox Code Playgroud)

这里虽然a 可以指向类型的对象B,但它实际上确实指向类型的对象A。当我们尝试进行动态转换以使其指向 a 时B,会失败。在第二次尝试中,我们再次得到一个指针,它不仅可以而且确实指向 类型的对象B。既然如此,B *在这种情况下,dynamic_cast 就会成功。

对于参考案例,基本情况并没有(太大)改变,只是abc成为引用而不是指针,并且我们通过捕获异常来注意到失败(@ReedCopsey 已经证明得足够好,我认为我没有有什么新的东西要添加)。


Mar*_*som 6

这是一个完整的示例,展示了如何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
}
Run Code Online (Sandbox Code Playgroud)

在现实世界中,您将尝试投射并非如此直接创建的指针,也许它们来自例如vector