当禁用RTTI时使用dynamic_cast

31

我很想知道在编译时使用动态转型但禁用RTTI(无论是在GCC上使用-fno-rtti还是在Visual Studio上使用/GR-)会发生什么。编译器是否会“退而求其次”使用static_cast?因为(至少在VS上)它只会发出一个警告,那么编译后的代码会做什么?

更具体地说,如果我在没有RTTI的情况下编译代码,并且我确定使用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() ;

8
为什么不尝试一下呢? - Eran Zimmerman Gonen
2
为什么你的代码要使用 dynamic_cast,如果你确定可以使用 static_cast 呢? - edA-qa mort-ora-y
@edA-qamort-ora-y:我知道这样做更好(实际上这就是我对有问题的代码所做的),我只是想知道会发生什么。 - Louen
1
@EranZimmerman:我发现在某些情况下会抛出std :: __non_rtti_object异常(但我仍然不知道原因)。 - Louen
6
想知道这种方法是否在任何平台和编译器上都可行,而不是准备一个定时炸弹在更换编译器时引爆。 - Antonio
4个回答

13

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

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

换句话说,标准似乎没有对你的问题做出任何说明。在这种情况下,标准不允许编译器关闭RTTI,因此对于每个编译器,您需要查看其文档以了解会发生什么。根据这篇文章,我认为这是一个编译器问题,而不是C++语言问题,正如标签所示。

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


12
在MSVC中,如果您的代码未启用RTTI编译,则在进行强制转换时,如果不能在运行时检查之前执行,则会抛出__non_rtti_object异常。

6

最简单的方法是尝试一下。

您会发现,一些动态转换将被标记为不合法。 有些则不会。例如,当您使用dynamic_cast进行向上转型到一个明确的基类时,转换在编译时已知。

补充说明
关于“由于(至少在VS上)它只发出警告 ...” 忽略警告可能会带来危险。最好的做法是确保您的代码没有警告,并将警告级别设置得非常高(并可能转换为错误)。其次是查看每个警告并确保没有发生任何异常情况。在这种情况下,会发生某些异常情况。您确实不应关心如何实现这种异常情况。您应该关心的是摆脱它。


我知道通常最好的做法是消除警告,而不是忽略它。我所说的“它只是发出一个警告”的意思是编译器仍然接受(但不赞成)这段代码,并将其编译成某些东西。 - Louen
1
“something”的具体含义取决于实现。当禁用RTTI时,标准变得无关紧要。 - David Hammen

2

试一下:

#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


2
编译器行为推导规则的问题在于,你可能会遇到编译器错误并依赖错误的规则。 - Slava

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接