好吧,我知道可移植性不是 C++ 的强项,但我必须让我的代码在 Mac 和 Windows 上运行。我已经提出了一种解决方案,但它并不完美,我有兴趣看看是否有人可以提出更好的解决方案。
我需要在多个 DLL/包中使用类层次结构 - 例如,我有一个抽象基类 BaseClass;我扫描给定目录中的 DLL,对于每个 DLL,我查找工厂方法基类* 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
}
这里存在问题:虽然它可以在带有 Visual Studio 的 Windows 上运行(可能是由于 MS declspec 扩展),但在编译时它在 Mac 上失败(现在不确定它是否在调试时失败,但我确信它在发布时失败)与海湾合作委员会。原因很简单,即使不是很明显:可执行文件和动态库是分开编译的。虽然它们都包含 BaseClass、ActionClass、DescriptionClass 的声明 - 这些类不是the same,它们只是二进制文件和 DLL 中存在的“相同副本”。所以实际上,我在DLL中创建的是一个dll'BaseClass*,它恰好与main'Baseclass*具有相同的内存布局,因此指针是兼容的,所以当我将指针从DLL传递到EXE时,它一切都“按预期”进行。 OTOH,当我进入更复杂的类层次结构时,dll'ActionClass 和 main'ActionClass 的 vtables/RTTI 不再相同(尽管在源代码中它们是相同的),所以当我尝试转换(通过dynamic_cast)一个 main 'BaseClass* 到 main'ActionClass* 我得到一个 null 结果 -> 因为我的指针实际上指向 dll'BaseClass 对象/dll'ActionClass 对象,并且在 DLL 中我可以毫无问题地将“BaseClass*”转换为“ActionClass*” - 在主可执行文件中,由于 DLL 和 Action Class 的“主可执行文件”版本之间存在细微的运行时差异,我无法将 dll 的“BaseClass*”转换为“ActionClass*”。
我通过在 BaseClass 中声明一个虚拟方法(类似于“bool isActionClass()”)来“修复”这个问题,所以现在我可以区分......但我对这个解决方案不太满意。
GCC 有什么东西吗 - 例如一些类似于“__declspec”的声明 - 一种保证“主可执行文件”和“dll”中声明的同一类将100%兼容的方法?