9

dynamic_casts 较慢,但它们比static_casts 更安全(当然,当与对象层次结构一起使用时)。我的问题是,在我在调试代码中确保所有(动态)强制转换都是正确的之后,我有什么理由不将它们更改为static_casts 吗?

我计划使用以下构造来做到这一点。(顺便说一句,你能想出一个更好的名字assert_cast吗?也许debug_cast?)

#if defined(NDEBUG)

    template<typename T, typename U>
    T assert_cast(U other) {
        return static_cast<T>(other);
    }

#else

    template<typename T, typename U>
    T assert_cast(U other) {
        return dynamic_cast<T>(other);
    }

#endif

编辑: Boost 已经为此提供了一些东西:polymorphic_downcast. 感谢 PlasmaHH 指出这一点。

4

5 回答 5

4

不!dynamic_cast不仅仅是铸造。它可以检查对象的运行时类型。但它也可以遍历编译器不知道但只在运行时才知道的层次结构。static_cast不能那样做。

例如:

class A1
{ 
    virtual ~A1() {} 
};
class A2
{
    virtual ~A2() {} 
};

class B : public A1, public A2
{ };

A1 *a1 = new B;
A2 *a2 = dynamic_cast<A2*>(a1); //no static_cast!

A1 *x = ...;
if (B *b = dynamic_cast<B*>(x)) //no static_cast!
  /*...*/; 
于 2011-09-09T09:46:49.420 回答
2

您应该断言dynamic_cast成功:

template<typename T, typename U>
T *assert_cast(U *other) {
    T *t = dynamic_cast<T>(other);
    assert(t);
    return t;
}

当您确定它们等效时替换dynamic_cast为in 与删除您确定始终为非空的指针的空检查相同。static_cast出于性能原因,您可以这样做。

于 2011-09-09T09:44:13.373 回答
2

只要您已经使用运行时因素/变量/输入的所有可能组合进行了测试,当然可以。正如评论中提到的,这类似于删除断言。

考虑到您的演员表始终正确的必要保证,语言中没有任何内容会使这本质上不安全。不过,它确实让人觉得天生不安全,因为您可能永远无法做出这样的保证。


更新

Konstantin 已经证明,在处理多重继承时,这种技术仅适用于单步向上/向下继承树1

struct A1 { virtual ~A1() {} };
struct A2 { virtual ~A2() {} };
struct A3 { virtual ~A3() {} };

struct B : A1, A2 {};
struct C : A1, A3, A2 {};

int main() {
    A1* a1 = (rand() < RAND_MAX / 2 ? (A1*)new B : (A1*)new C);

    A2* p1 = dynamic_cast<A2*>(a1);
    // ^ succeeds, but is a cross-cast

    // A2* p2 = static_cast<A2*>(a1);
    // ^ ill-formed

    A2* p3 = static_cast<A2*>(static_cast<B*>(a1));
    // ^ must chain, instead.
    // but p3 is invalid because we never
    //   checked that `dynamic_cast<B*>(a1)` is valid.. and it's not

    // Instead, let's expand the `dynamic_cast`s into a chain, too:
    A2* p3 = dynamic_cast<B*>(a1);
    A2* p4 = dynamic_cast<A2>*(a1);
    // ^ p3 fails, so we know that we cannot use `static_cast` here
}

所以,你可以dynamic_caststatic_casts iff 替换你的 s:

  • 每个dynamic_cast只执行一个向上或向下的步骤;
  • 众所周知,每个dynamic_cast人总是会成功。

1实际上,这是一种简化,例如,向下转换适用于任意数量的步骤。但它是一个很好的经验法则。

于 2011-09-09T09:45:23.863 回答
1

我想这取决于项目。如果是核电站管理软件我更喜欢安全,如果是3D游戏我更喜欢性能。您永远无法确定dynamic_cast生产代码中的所有内容都是正确的。如果性能比安全更重要,则删除。

于 2011-09-09T09:47:25.180 回答
1

在我的调试代码中确保所有(动态)强制转换都是正确的之后,我有什么理由不将它们更改为 static_casts?

恕我直言,如果您 100% 确定所有 dynamic_cast<>内容都是正确的,那么没有理由不将它们更改为static_cast<>. 你可以改变它们。

于 2011-09-09T09:48:56.880 回答