繁体   English   中英

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

[英]How to work (portably) with C++ class hierarchies & dynamic linked libraries

好的,所以我知道可移植性不是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,但是接口略有不同。 我的第一个实现是简单地修改“共享头”并添加:

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
}

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

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

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

我实际上找到了我的问题的答案,因为我需要完全制定它,我做了一个更好的谷歌搜索:)它似乎是

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

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

这只有在启用RTTI时才有效。 您可能会在MSVC ++中自动启用,但gcc需要特定的链接开关。 有关详细信息,请参阅GCC FAQ

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM