【问题标题】:dynamic_cast vs dynamic library boundariesdynamic_cast 与动态库边界
【发布时间】:2019-11-12 00:51:59
【问题描述】:

我正在阅读“使用 Qt 4 进行 C++ GUI 编程”,我在其中找到了以下语句

与标准 C++ 的 dynamic_cast() 不同,Qt 的 qobject_cast() 可以跨动态库边界正常工作。

类似的声明出现在官方 Qt 文档中

https://doc.qt.io/qt-5/qobject.html#qobject_cast

这是什么意思?我们究竟在哪里不能在 C++ 中使用 dynamic_cast ? 那么虚函数呢?将它们与动态链接库一起使用是否安全?

【问题讨论】:

  • @G.M.好吧,这个问题的唯一答案只是简单地说“基本上,RTTI 在模块边界上是不可靠的”,而我要求解释它到底是什么意思(我不是一个有经验的程序员)。
  • 至少,如果您可以只使用 C ABI 制作一个微不足道的接口,您的代码将更加可移植和健壮。我通常会尽量避免跨库边界传递 C++ 对象和任何非 C 对象。例外情况也是如此。此外,微薄的接口减少了子系统之间的耦合。

标签: c++


【解决方案1】:

在概念上,dynamic_cast 可以跨模块边界工作。但是,一些编译器/链接器以性能的名义偷工减料。加载共享库时提高性能的方法之一是尽可能少地使其他库可见的符号。这减少了加载器必须做的工作量,因为它不必解析尽可能多的符号。 RTTI 符号位于砧板上,默认情况下不暴露给其他模块。 GCC 的文档描述了这一点以及解决方法here

不幸的是,这让 RTTI 变得一团糟。构建对象的模块和执行dynamic_cast 的模块可能拥有它们自己的,否则相同的类型的RTTI 符号。这使得它们在 dynamic_cast 在不同的模块中执行时显示为不同的类型,导致 dynamic_cast 意外返回 nullptr,或抛出 std::bad_cast 以供参考。

在链接和调用 dlopen() 时需要特别小心,以便加载程序知道在模块加载时解析模块之间的 RTTI 符号。

此外,Qt 过去一直支持platforms,它们要么不支持 RTTI,要么 RTTI 会产生太多开销。因此,qobject_cast 的发明是为了完全消除对 RTTI 的依赖,同时仍然提供一种在多态类型之间进行转换的方法。

回答您的其他问题:

  • 您可以在 RTTI 可用的任何地方使用 dynamic_cast,但动态链接会使这变得困难。
  • 虚拟函数work fine 在这些场景中作为加载器解析函数的符号。

【讨论】:

    猜你喜欢
    • 2018-04-29
    • 2019-06-07
    • 1970-01-01
    • 2022-07-16
    • 2020-12-22
    • 2011-06-06
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    相关资源
    最近更新 更多