假设我们有共享库,其中包含以下非常简单的
Type.h
:
struct Base
{
virtual ~Base() = default;
};
struct Derived final : Base
{
Derived();
};
,
Type.cpp
:
#include "Type.h"
Derived::Derived() = default;
和
main.cpp
程序:
#include "Type.h"
int main()
{
std::shared_ptr<Base> pr;
pr = std::make_shared<Derived>();
auto dyncast = dynamic_cast<Derived *>(pr.get());
if (dyncast) {
std::cout << "OK\n";
} else {
std::cout << "!!! FAIL\n";
}
return 0;
}
使用
-O2
标志编译:
> clang++ -dynamiclib -L. -std=gnu++20 -O2 -o libOut.dylib Type.cpp
> clang++ -o out main.cpp -L. -lOut -O2 -std=gnu++20
> ./out
由于某种原因,使用 XCode 16 程序无法
dynamic_cast
并输出失败行。
以下“修复”了该问题:
final
声明中删除 Derived
Derived
构造函数virtual
添加其他
Derived
-O2
据我了解,这里发生了某种优化,导致
dynamic_cast
失败,但是,在我看来,这看起来像是一个错误,而且是一个巨大的错误。我是不是错过了什么?
是否有某种解决方法/编译器标志可以使此工作正常?
谢谢你。
问题是虚拟析构函数是在标头中隐式定义的。
这会导致每个库/可执行文件对于给定类型都有自己的虚拟表。结果,RTTI 出现问题,
dynamic_cast
失败。
我已在我的 MacOS 计算机上重现了您的问题,并在下面介绍修复后,它可以正常工作:
Type.h
#pragma once
struct Base
{
virtual ~Base();
};
struct Derived final : Base
{
Derived();
~Derived();
};
Type.cpp
#include "Type.h"
Base::~Base() = default;
Derived::Derived() = default;
Derived::~Derived() = default;
在此表格中,您将获得保证,每种类型只有一张真实表格,并且位于
libOut.dylib
的内部