dynamic_cast由于隐藏符号什么时候会失败?

7
根据gcc关于可见性的维基页面(https://gcc.gnu.org/wiki/Visibility,请查看“C++异常问题(请阅读!)”部分),以及似乎是一个示例(隐藏符号时dynamic_cast失败),隐藏类可能导致有效的dynamic_cast失败。 我想通过示例确切地了解何时会发生这种情况:是否有人可以给我一个小的示例来正确理解这种影响?

以下是我尝试理解的内容(在Linux上使用gcc > 7):

据我所知,我需要发生vague linkage,这种情况发生在基类没有关键方法时。因此,我尝试使用此基础层次结构:

class A {
  virtual ~A();
  virtual void print() = 0;
}

和派生类:

class B : public A {
  ~B() override;
}

然后我将拥有两个实现类A_imlB_impl,它们只会打印出它们的名称:

#include "a.hpp"

class AImpl : public A {
  ~AImpl() override = default;
  void print() override { printf("AImpl"); }
}

#include "b.hpp"

class BImpl : public B {
  ~BImpl() override = default;
  void print() override { printf("BImpl"); }
}

现在我理解的是,我需要将这些类链接到两个不同的共享库中,并使用-fvisibility-hidden(也许是-fvisibility-inlines-hidden,但这里并不重要)隐藏它们的符号。

这样应该会导致这两个类的虚函数表在两个共享库中被发射(并隐藏),一个库中使用另一个库的对象进行dynamic_cast(例如)应该会失败,因为这两个层次结构是不同的。

例如,让第一个库执行以下操作:

factory.hpp:

class A;
A * create();

factory.cpp相关:

#include "factory.hpp"
#include "b_impl.hpp"

A * create() {
  return new BImpl();
}

我将把这个和上面的类层次结构链接到一个共享库中。
另一个:

function.hpp

void doSomething();

function.cpp

#include "function.hpp" 
#include "factory.hpp"

void doSomething() {
  A * b = create();
  b.print();
  if(dynamic_cast<B *>(b)) printf("Cast was correct");
}

(另一个共享库,链接到第一个和上面的层次结构)。

这是一个稍微简化的例子 - 当然,我会将所有内容包装在命名空间中等等,但为了简洁起见,我省略了这些内容。查看 objdump 等内容,似乎两个共享库实际上都包含了 AB 的虚表,并且其中一个被隐藏了,但转换成功:我只需将两者链接到某个带有主函数的其他库中(例如),它就会打印出“转换正确”。

有人能帮我改变这个示例或指向不同的示例,以便看到该效果并理解其细微差别吗?


function.cpp 如何知道 B 是一个类?目前代码中有一个 function.hpp 的包含,其中只包含一个函数声明,以及一个 factory.hpp 的包含,其中包含了一个不完整类型 A 的声明和一个函数声明。编译不应该失败吗? - JaMiT
1个回答

0

这些对象的 vtable 没有被隐藏,否则调用虚方法将不可能。每个类实例中都有一个指向 vtable 的指针。如果这些对象的 typeinfo 不可用,例如如果 dll 是使用 -fno-rtti 编译的,则可能会出现问题。vtable 仍然可用,但是动态转换将无法工作。


友情提示:问题是:“由于隐藏符号, dynamic_cast 何时失败?” - YSC

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