gpt4 book ai didi

c++ - 如何(可移植地)使用 C++ 类层次结构和动态链接库

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:37:13 25 4
gpt4 key购买 nike

好吧,我知道可移植性不是 C++ 的强项,但我必须让我的代码在 Mac 和 Windows 上运行。我想出了一个解决方案,但它并不完美,我很想看看是否有人可以提出更好的解决方案。

我需要在几个 DLL/bundle 中使用一个类层次结构——例如,我有一个抽象基类 BaseClass;然后我扫描给定的 DLL 目录,对于每个 DLL,我寻找工厂方法 BaseClass* CreateObject(); - 它返回一个“BaseClass”。我有一个“共享头文件”,它包含在“主可执行文件”和 DLL 中,它像这样声明 BaseClass

#ifdef _MAC
#define DECLSPEC
#else
#ifdef COMPILING_DLL
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif
#endif

class DECLSPEC BaseClass{
[.. base "interface" declaration .. ]
}

然后,在我的 DLL 中,我通常会包含 BaseClass 声明,并声明我自己的“具体”类:

class MyDllClass:public BaseClass{
[.. actual DLL class definition/implementation here goes here ...]
}

到目前为止,还不错。现在出于某种原因,我需要在我的主要可执行文件中区分两种不同类型的 BaseObjects - 假设我有一个 DescriptionClass 和一个 ActionClass,它们都是 BaseClass,但接口(interface)略有不同。我的第一个实现是简单地修改“共享 header ”并添加:

class DECLSPEC DescriptionClass{
[.. base "Description interface" declaration .. ]
}

class DECLSPEC ActionClass{
[.. base "Action interface" declaration .. ]
}

然后我的 DLL 将变成:

class MyDllClass:public ActionClass /* or DescriptionClass, depending on case*/ {
[.. actual DLL class definition/implementation here goes here ...]
}

在我的主要可执行文件中,我会像这样使用它:

BaseClass* obj = CreateObjectFromDLL("path_to_dll");
ActionClass* action_obj = dynamic_cast<ActionClass*>(obj);
if(action_obj){
// Do the stuff that is relevant for Action objects
}
DescriptionClass* description_obj = dynamic_cast<ActionClass*>(obj);
if(description_obj){
// Do the stuff that is relevant for Description objects
}

这就是问题所在:虽然它可以在带有 Visual Studio 的 Windows 上运行(可能是由于 MS declspec 扩展),但它在 Mac 上会失败(现在不确定它是否在调试时失败,但我确定它在发布时失败) 用 GCC 编译时。原因很简单,即使不是很明显:可执行文件和动态库是分开编译的。尽管它们都包含 BaseClass、ActionClass、DescriptionClass 的声明 - 这些类相同,但它们只是存在于二进制文件和 DLL 中的“相同拷贝”。所以实际上,我在 DLL 中创建的是一个 dll'BaseClass* ,它恰好与 main'Baseclass* 具有相同的内存布局,所以指针是兼容的,所以当我将指针从 DLL 传递到 EXE 时,它一切都“按预期”工作。 OTOH,当我进入一个更复杂的类层次结构时,dll'ActionClass 和 main'ActionClass 的 vtables/RTTI 不再相同(尽管在源代码中它们是相同的),所以当我尝试转换(通过 dynamic_cast)一个 main 'BaseClass* 到 main'ActionClass* 我得到一个空结果 -> 因为我的指针实际上指向一个 dll'BaseClass 对象/dll'ActionClass 对象,虽然在 DLL 中我可以毫无问题地将“BaseClass*”转换为一个“ActionClass*”——在主可执行文件中,我无法将 dll 的“BaseClass*”转换为“ActionClass*”,因为 DLL 和“主可执行文件”版本的 Action Class 之间存在细微的运行时差异。

我已经通过在 BaseClass 中声明一个虚拟方法(类似于“bool isActionClass()”)来“修复”这个问题,所以现在我可以区分...但我对这个解决方案不是很满意。

GCC 有什么东西吗?一些类似于“__declspec”的声明 - 一种保证在“主可执行文件”和“dll”中声明的相同类将 100% 兼容的方法?

最佳答案

我实际上找到了我的问题的答案,因为我需要完整地表述它,而且我做了更好的谷歌搜索:)好像是

__attribute__((dllimport)) // import
__attribute__((dllexport)) // export

会尝试的,我想我也会把问题留在这里,以防其他人偶然发现这个问题(并且作为对人们的警告,“主二进制文件”和 DLL 中包含的相同头文件通常会导致不同实际实现,具体取决于编译器选项 - 除非您将适当的 dllimport/export 属性放在类上)。

关于c++ - 如何(可移植地)使用 C++ 类层次结构和动态链接库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1564802/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com