有没有办法让不同编译器构建的c ++ dll相互兼容?这些类可以有工厂方法来创建和销毁,因此每个编译器都可以使用自己的new/delete(因为不同的运行时有自己的堆).
我尝试了以下代码,但它崩溃了第一个成员方法:
interface.h
#pragma once class IRefCounted { public: virtual ~IRefCounted(){} virtual void AddRef()=0; virtual void Release()=0; }; class IClass : public IRefCounted { public: virtual ~IClass(){} virtual void PrintSomething()=0; };
test.cpp用VC9编译,test.exe
#include "interface.h" #include#include int main() { HMODULE dll; IClass* (*method)(void); IClass *dllclass; std::cout << "Loading a.dll\n"; dll = LoadLibraryW(L"a.dll"); method = (IClass* (*)(void))GetProcAddress(dll, "CreateClass"); dllclass = method();//works dllclass->PrintSomething();//crash: Access violation writing location 0x00000004 dllclass->Release(); FreeLibrary(dll); std::cout << "Done, press enter to exit." << std::endl; std::cin.get(); return 0; }
a.cpp用g ++ g ++编译.exe -shared c.cpp -o c.dll
#include "interface.h" #includeclass A : public IClass { unsigned refCnt; public: A():refCnt(1){} virtual ~A() { if(refCnt)throw "Object deleted while refCnt non-zero!"; std::cout << "Bye from A.\n"; } virtual void AddRef() { ++refCnt; } virtual void Release() { if(!--refCnt) delete this; } virtual void PrintSomething() { std::cout << "Hello World from A!" << std::endl; } }; extern "C" __declspec(dllexport) IClass* CreateClass() { return new A(); }
编辑:我将以下行添加到GCC CreateClass方法,文本被正确打印到控制台,所以它的defenatly函数调用,这就是杀死它.
std::cout << "C.DLL Create Class" << std::endl;
我想知道,COM如何设法维护甚至跨语言的二进制兼容性,因为它基本上所有具有继承性的类(尽管只有单个)因此也是虚函数.如果我不能重载运算符/函数,只要我能维护基本的OOP内容(即类和单继承),我就不会受到严重的打扰.
如果您降低期望并坚持简单的功能,您应该能够混合使用不同编译器构建的模块.
类和虚函数的行为方式由C++标准定义,但实现的方式取决于编译器.在这种情况下,我知道VC++构建的对象具有虚拟函数,在对象的前4个字节中具有"vtable"指针(我假设是32位),并指向方法条目的指针表点.
这一行:dllclass->PrintSomething();
实际上相当于:
struct IClassVTable { void (*pfIClassDTOR) (Class IClass * this) void (*pfIRefCountedAddRef) (Class IRefCounted * this); void (*pfIRefCountedRelease) (Class IRefCounted * this); void (*pfIClassPrintSomething) (Class IClass * this); ... }; struct IClass { IClassVTable * pVTab; }; (((struct IClass *) dllclass)->pVTab->pfIClassPrintSomething) (dllclass);
如果g ++编译器以与MSFT VC++不同的方式实现虚函数表 - 因为它可以自由地执行并且仍然符合C++标准 - 这只会像你演示的那样崩溃.VC++代码要求函数指针位于内存中的特定位置(相对于对象指针).
它通过继承变得更加复杂,并且真的,真的,复杂的多重继承和虚拟继承.
Microsoft一直非常公开VC++实现类的方式,因此您可以编写依赖于它的代码.例如,MSFT分发的许多COM对象头在头中都有C和C++绑定.C绑定暴露了他们的vtable结构,就像我上面的代码那样.
另一方面,GNU-IIRC已经开放了在不同版本中使用不同实现的选项,并且只保证用它的编译器构建的程序(仅!)将符合标准行为,
简短的回答是坚持简单的C风格函数,POD结构(普通旧数据;即没有虚函数),以及指向不透明对象的指针.
如果你这样做,你几乎肯定会遇到麻烦 - 而其他评论者认为C++ ABI在某些情况下可能是相同的,两个库使用不同的CRT,不同版本的STL,不同的异常抛出语义,不同优化......你正走向疯狂的道路.