【问题标题】:Dynamic_cast compatibility?Dynamic_cast 兼容性?
【发布时间】:2017-11-10 16:58:48
【问题描述】:

我正在阅读有关 dynamic_cast 的内容,然后我遇到了以下语句 (from cplusplus.com):

兼容性说明:这种类型的 dynamic_cast 需要 Run-Time Type 用于跟踪动态类型的信息 (RTTI)。一些编译器 支持此功能作为默认禁用的选项。这 需要使用 dynamic_cast 启用运行时类型检查 与这些类型一起正常工作。

例子之后:

// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class Base { virtual void dummy() {} };
class Derived: public Base { int a; };

int main () {
  try {
    Base * pba = new Derived;
    Base * pbb = new Base;
    Derived * pd;

    pd = dynamic_cast<Derived*>(pba);
    if (pd==0) cout << "Null pointer on first type-cast.\n";

    pd = dynamic_cast<Derived*>(pbb);
    if (pd==0) cout << "Null pointer on second type-cast.\n";

  } catch (exception& e) {cout << "Exception: " << e.what();}
  return 0;
}

作者所说的“这种类型的dynamic_cast”是什么意思? dynamic_cast 不是仅用于多态类(几乎)吗?他提到这个 RTTI 是动态转换工作所必需的,这是否意味着您必须谨慎使用 dynamic_cast,因为您不知道编译器是否完全支持它,因此它比其他转换更具风险不需要这个 RTTI 的算子?

【问题讨论】:

  • 您应该对 cplusplus.com 所说的一切持保留态度。例如,我不知道有任何 C++ 编译器默认禁用 RTTI。
  • 如果您为 C++ 禁用 RTTI,您要么有一个非常 充分的理由并且真的 知道您在做什么,并且有分析来支持您的声明这很重要。要么;你是一个白痴。顺便说一句,停止阅读 cplusplus.com 并改为阅读 cppreference.com 和其他好的资源。
  • @NeilButterworth 我可以想象一个非常有限的嵌入式系统的编译器可能会认为 RTTI 开销太大,默认情况下将其关闭,但我已经多年没有在该领域工作了也没遇到过。
  • 这几乎是重复的:stackoverflow.com/questions/2253168/… 和来自那里的链接
  • 无论如何,如果您禁用 RTTI,例如通过使用-fno-rtti,我想你会在使用动态转换时遇到编译器错误(至少我明白了)。所以我认为它是“保存”,因为我认为它不会在禁用 RTTI 的情况下编译。

标签: c++ casting dynamic-cast


【解决方案1】:

rtti 在运行时很昂贵,一些嵌入式系统使用标志编译,禁用它。它给你的只是dynamic_casttypeid

因此,我解释

因为你不知道它是否被编译器完全支持

作为

因为您的代码可能是在禁用 rtti 的情况下编译的。

【讨论】:

  • “rtti 在运行时很昂贵” - 相对于什么?
  • @CaptainObvlious 相对于不生成它
  • 虽然是真的,但我看不出这是如何回答问题的。
【解决方案2】:

兼容性说明与前一段(和代码示例)有关:

但是dynamic_cast 也可以向下转型(从指向基的指针转换为指向派生的指针)多态类(那些具有虚拟成员的)当且仅当指向的对象是目标类型的有效完整对象。

确实如此:向下转换需要一个多态类型的对象,并且 RTTI 在运行时遍历对象的继承树。

dynamic_cast的另一种类型在那个之前的段落中解释过:

这自然包括指针向上转换(从派生指针转换为基指针),与隐式转换所允许的方式相同。

此处不需要 RTTI,因为对象的基数始终是静态已知的。

因此,您只需完整阅读周围的文字,即可了解您正在阅读的单词的上下文。

不过,我会注意到,根据我的经验,默认情况下禁用 RTTI 的编译器基本上是闻所未闻的。我并不是说不存在——可能有一些针对嵌入式平台的特定行业的编译器,它们这样做是为了在他们的 Makefile 中为程序员节省几个字节。但据我所知,大多数人使用的编译器(GCC、Clang、Visual Studio、ICC、Comeau)都将 RTTI 打包为标准并保持打开状态,直到您要求将其关闭。

【讨论】:

  • 谢谢,这是否意味着您在使用 dynamic_cast 时必须比使用其他强制转换运算符(如 static_cast)时更加谨慎?
  • @OfT:我不这么认为。您认为应该采取什么样的谨慎措施?
  • 我的意思是因为它可能是编译器不完全支持 dynamic_cast 而也许 static_cast 和其他强制转换运算符可以正常工作..
  • @OfT:我不认为这意味着你需要任何谨慎; you should get a compilation error if you can't use dynamic_cast in the way you want.
  • 啊,太好了,所以如果它最适合给定情况,我应该毫不犹豫地使用特定的转换运算符,例如用于多态类的 dynamic_cast?
【解决方案3】:

您提到的部分中的作者提到了将dynamic_cast 与多态类型一起使用的情况:更准确地说,当您编写类似dynamic_cast&lt;X*&gt;(p) 的内容时。 在这种情况下,您将需要运行时类型信息,以便完全可以使用 dynamic_cast(参见下面的示例)。

您可以通过使用提到的编译器选项-fno-rtti 使编译器禁止生成有关每个具有虚函数的类的此类信息,但很少推荐这样做。

“其他”案例是关于dynamic_castvoid*s的使用。

例如,考虑以下代码:

class A {
public:
  virtual ~A() = default;
};

class B : public A {};

int main()
{
  A *p = new B();
  void *pv = dynamic_cast<void*>(p);
  //B *pb = dynamic_cast<B*>(p);

  delete p;

  return 0;
}

如果你用g++ test.cpp -std=c++11 -fno-rtti 编译代码,那就没问题了。但是,如果您在取消注释 B *pb = dynamic_cast&lt;B*&gt;(p); 后执行相同操作,编译器将针对该特定行给出以下错误消息:error: ‘dynamic_cast’ not allowed with -fno-rtti。请注意,即使使用 -fno-rtti(已手动或默认设置),转换为 void* 也有效。

【讨论】:

  • dynamic_cast 只能用于多态类型
  • @M.M 不完全正确。在某些情况下,它可以用于非多态类型。但是,在所有这些情况下,使用 dynamic_cast 是没有意义的,因为可以进行隐式转换。 (在模板函数中可能存在一些有用的极端情况。)
  • @aschepler 好的,我应该说通过dynamic_cast 向下转换只能使用多态类型来完成
  • 感谢 cmets,试图扩展我的答案以更好地反映我的观点。
猜你喜欢
  • 1970-01-01
  • 2016-04-12
  • 2016-02-19
  • 2012-08-18
  • 2014-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多