【问题标题】:dynamic_cast with RTTI disabled禁用 RTTI 的 dynamic_cast
【发布时间】:2011-12-02 23:25:17
【问题描述】:

我很想知道在禁用 RTTI 的情况下使用动态转换编译代码时会发生什么 (在 GCC 上使用 -fno-rtti 或在 Visual Studio 上使用 /GR-)。编译器是否“回退”到 static_cast ?由于(至少在 VS 上)它只会发出警告,那么编译后的代码会做什么?

更具体地说,如果我在没有 RTTI 的情况下编译一个我确信 dynamic_cast 不会出错的代码(即 dynamic_cast 可以安全地被 static_cast 替换),会发生什么坏事:

class A{ /*...*/ } ;
class B : public A {
    int foo() { return 42 ;}
} ;
//...
A * myA = new B() ;
int bar = (dynamic_cast<B*>(myA))->foo() ;

【问题讨论】:

  • 为什么不试试呢?
  • 如果您确定可以使用static_cast,为什么您的代码使用dynamic_cast
  • @edA-qamort-ora-y :我知道这样更好(实际上这是我对违规代码所做的),我只是想知道会发生什么
  • @EranZimmerman :我发现抛出了 std::__non_rtti_object ,但仅在某些情况下(我仍然不知道为什么)
  • @EranZimmerman 想知道这在任何平台和编译器上是否总是有效,而不是在切换编译器时准备一颗准备爆炸的定时炸弹。

标签: c++ rtti dynamic-cast


【解决方案1】:

阅读标准,在 5.2.7/6 中我们发现除非目标是源的明确基础,否则源必须是多态类型。然后在 10.3/1

虚函数支持动态绑定和面向对象 编程。声明或继承虚函数的类是 称为多态类。

换句话说,标准似乎没有说明您的问题。在这种情况下,标准不允许编译器关闭 RTTI,因此对于每个编译器,您需要检查其文档以查看会发生什么。基于此阅读,我认为这是一个编译器问题,而不是标签所示的 C++ 语言问题。

或者,当您知道足够时,只需使用static_cast 即可完全避免该问题。

【讨论】:

    【解决方案2】:

    在 MSVC 中,如果您的代码未在启用 RTTI 的情况下编译,如果没有运行时检查就无法执行转换,则会引发 __non_rtti_object 异常。

    【讨论】:

      【解决方案3】:

      找出答案的最简单方法是尝试一下。

      您会发现一些您的动态转换将被标记为非法。有些不会。例如,当您使用动态转换向上转换为明确的基类时,转换在编译时是已知的。

      附录
      重新“因为(至少在 VS 上)它只发出警告 ...” 忽略警告后果自负。最好的办法是确保您的代码在没有警告的情况下编译,警告级别设置得非常高(并且可能转换为错误)。第二好的方法是查看收到的每一个警告,并确保不会发生任何不愉快的事情。在这种情况下,会发生一些不愉快的事情。你真的不应该关心那个不愉快的事件是如何实现的。你应该关心的是摆脱它。

      【讨论】:

      • 我知道删除警告原因通常比忍受它更好。我所说的“它只发出警告”的意思是编译器仍然接受(但不赞成)代码并将其编译成某种东西。
      • 那个“东西”是依赖于实现的。该标准在禁用 RTTI 方面没有实际意义。
      【解决方案4】:

      试试吧:

      #include <iostream>
      #include <typeinfo>
      #include <typeindex>
      #include <memory>
      #include <vector>
      #include <array>
      #include <string>
      
      class Base {
      public:
        virtual ~Base() {
        }
      };
      
      class A: public Base {
      };
      
      class B: public Base {
      };
      
      using namespace std;
      
      int main() {
        A *a = new A;
        auto *ptr = dynamic_cast<B*>(a);
      
        if (!ptr)
          std::cout << "failed to cast" << std::endl;
      
        return 0;
      }
      

      没有-fno-rtti,程序编译,输出为:

      failed to cast
      

      -fno-rtti,程序编译失败:

      main.cpp:25:35: error: ‘dynamic_cast’ not permitted with -fno-rtti
           auto* ptr = dynamic_cast<B*>(a);
                                         ^
      

      您也可以在这里在线测试:https://onlinegdb.com/pYTQu2ne2

      【讨论】:

      • 通过编译器行为推断规则的问题,您可能会遇到编译器错误并依赖错误的规则。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-27
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      相关资源
      最近更新 更多