【问题标题】:How to identify failed casts using dynamic_cast operator?如何使用 dynamic_cast 运算符识别失败的演员表?
【发布时间】:2012-07-16 18:17:31
【问题描述】:

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

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

我想得到两个代码sn-p显示在转换指针和转换引用的情况下失败的转换。

【问题讨论】:

  • 您是否要求提供测试指针是否为空的代码以及捕获异常的代码示例?
  • 没有。我不明白斯科特提到的演员阵容如何失败。一个代码 sn-p 肯定会有所帮助。
  • @JamesMcNellis:请记住,我们都是从初学者开始的。我还是从 Reed 那里得到了代码 sn-p。

标签: c++ pointers reference dynamic-cast


【解决方案1】:

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

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
}

【讨论】:

  • @LinuxPenseur 检查假设“a”具有有效值。您必须先检查(分配)。 dynamic_cast 检查是检查 A 是否可以安全地转换为 "B" - 所以检查是针对 bNULL - 即:b 为 null 而 a 不为 null。
  • @ReedCopsey:我的safe cast 是什么意思。 b在什么情况下可以变成NULL?
  • dynamic_cast 用于多态类(具有virtual 函数)并且它执行运行时检查,返回NULLpointer。使用dynamic_cast,您是在告诉它完全按照您的要求进行操作,而不是尝试各种类型的转换的 C 样式转换。 dynamic_cast 也用于当您不知道要转换的对象时,而不是 static_cast 用于非多态类并且转换上的两种类型都是已知的
  • @LinuxPenseur: new() 在失败时不一定返回空指针,您可能还需要在这里检查异常。如果a 不是B 的实例,b 将变为NULL
  • @Suzi 和 != NULL 一样
【解决方案2】:

根据 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 已经已经表现得足够好,我认为我没有什么要补充的)。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-25
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 2011-07-04
      • 2018-11-26
      相关资源
      最近更新 更多