27

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

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

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

4 回答 4

13

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

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

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

或者,您可以通过仅static_cast在知道足够时使用来完全避免该问题。

于 2011-10-07T13:46:39.063 回答
10

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

于 2011-10-07T14:38:08.287 回答
6

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

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

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

于 2011-10-07T12:21:43.663 回答
1

就试一试吧:

#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

于 2021-06-02T15:38:34.917 回答