【问题标题】:static_cast and RTTI vs dynamic_caststatic_cast 和 RTTI 与 dynamic_cast
【发布时间】:2012-09-25 17:40:33
【问题描述】:

请注意以下代码。据我所知,dynamic_cast 比 static_cast 慢。因为它在运行时评估类型。 我的疑问是,如果我们将 static_cast 与 typeid() 一起使用如下,它是否需要与动态转换相同的时间? 会比 dynamic_cast 快吗?

class Shape
{ 
public:
  virtual ~Shape(){}
};
class Circle : public Shape{ };
class Square : public Shape{ };

使用 RTTI 进行静态转换:

Circle c;
Shape* s = &c; // Upcast: normal and OK

// More explicit but unnecessary:
s = static_cast<Shape*>(&c);
// (Since upcasting is such a safe and common
// operation, the cast becomes cluttering)

Circle* cp = 0;
Square* sp = 0;

// Static Navigation of class hierarchies
// requires extra type information:
if(typeid(s) == typeid(cp)) // C++ RTTI
    cp = static_cast<Circle*>(s);
if(typeid(s) == typeid(sp))
    sp = static_cast<Square*>(s);
if(cp != 0)
    cout << "It's a circle!" << endl;
if(sp != 0)
    cout << "It's a square!" << endl;

动态演员:

Circle c;
Shape* s = &c; // Upcast: normal and OK

s = &c;
Circle* cp = 0;
Square* sp = 0;
cp = dynamic_cast<Circle*>(s);
    if(cp != 0)
    cout << "It's a circle!" << endl;
sp = dynamic_cast<Square*>(s);
if(sp != 0)
    cout << "It's a square!" << endl;

【问题讨论】:

  • 这只有在您取消引用指向对象的指针时才有效。只有这样typeid 才能使用动态类型的对象,而不是只给你Circle*Shape*
  • 嗨 Pileborg,感谢您的建议,我只想知道它们之间的时间差异。我会检查任何预定义的函数

标签: c++ dynamic-cast static-cast


【解决方案1】:

测试类型然后执行static_cast 会更快,但是这些操作并不等效,因为这只会允许向下转换为最派生的类型(任何中间级别都不会与typeid 匹配)。我会使用dynamic_cast,因为它更健壮(例如,如果有人扩展您的类型并传递指针,则不会中断)。

如果dynamic_cast 的性能在您的应用程序中是一个问题,您应该重新考虑设计。虽然typeid + static_castdynamic_cast 快,但不必打开对象的运行时类型比它们中的任何一个都快。

【讨论】:

    【解决方案2】:

    这些代码示例在逻辑上并不相同。您忘记了dynamic_cast 将类继承带入帐户,并且比较 typeid() 仅比较继承树的 leaf 部分。 typeid 给您的唯一信息是“与该对象的实际类型相关的一些唯一标识符”。单独使用 typeid() 无法检查是否可以强制转换为公共基的指针,您只能检查 runtimetype-of-that 是否与 runtimetype-of-otherthing 完全相同。

    这么说,我认为static_cast+typeid在一般意义上应该会快一些,但在某些情况下只会给出错误的答案。

    【讨论】:

    • typeid 仅在运行时为您提供与对象的实际类型相关的唯一标识符,不是吗?单独的 typeid() 是不够的??我认为它会像 dynamic_cast 那样进行运行时检查。我错了吗,请纠正我
    • 是的,它只在运行时有效。在编译时它是未知的,您的任何比较都无法被优化掉。
    • @ranganath111:关键是如果你有ABC的层次结构,typeid你只能测试对象是否是最派生的类型C,但不是B。如果您的代码不关心实际类型是C 还是C',而只是在层次结构的B 分支中,则可以使用dynamic_cast 而不是typeid。另请注意,打开类型通常不是一个好主意,typeid 更是如此。如果将来某个时间有人使用D 扩展层次结构,在任何条件下都不会匹配。
    【解决方案3】:

    我想任何体面的编译器都能够将两个示例优化为相同的代码。但是,找出答案的唯一方法是衡量您的特定工具链的结果。

    【讨论】:

    • 实际上编译器无法优化这种依赖于运行时信息的东西(也许他们可以用 _this 特定的例子,但是引入任何编译器无法知道或预测的东西,它会消失) . typeid 比较在两个指针之间进行单个比较,而dynamic_cast 遍历继承树,因此理论上前者应该更快。但是,是的,您应该衡量结果。
    • @SethCarnegie 我当然不是要暗示编译器会优化 RTTI,尽管我同意在一个非常简单的情况下这是可能的。相反,我相信它可以推断出typeidstatic_cast 的这种用法只是dynamic_cast 的简单用户实现,因此在任何一种情况下它都会输出相同的代码。
    • 嗯,static_casttypeid 这样使用绝对不是dynamic_cast。正如我之前所说,它们做的事情完全不同:一个直接比较两种类型,另一种比较多种类型。同样dynamic_cast 在失败时也有不同的行为,因此编译器将static_cast 版本更改为dynamic_cast 会出错。
    • @SethCarnegie - 正是我写的,考虑扩展我的帖子吗?如果你觉得不清楚,我可以把它变成维基
    • @SethCarnegie 我明白你的意思,我的回答集中在给出的确切代码上,不考虑继承树中附加类的可能性。我假设在链接时间不存在其他类的情况下,我是正确的,但总的来说,我是不正确的。谢谢你的澄清。
    【解决方案4】:

    只有一种方法可以确定。用 std::chrono 和 high_resolution_clock 测量它。

    【讨论】:

    • 我会检查并通知您。非常感谢
    猜你喜欢
    • 2011-06-06
    • 1970-01-01
    • 2010-11-18
    • 2014-05-29
    • 2011-01-16
    • 1970-01-01
    • 2010-09-06
    相关资源
    最近更新 更多