異なるコンパイラでビルドされた C++ dll を相互に互換性を持たせる方法はありますか? クラスは作成と破棄のためのファクトリ メソッドを持つことができるため、各コンパイラは独自の新規/削除を使用できます (異なるランタイムには独自のヒープがあるため)。
次のコードを試しましたが、最初のメンバー メソッドでクラッシュしました。
インターフェイス.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;
};
VC9 でコンパイルされた test.cpp、test.exe
#include "interface.h"
#include <iostream>
#include <windows.h>
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;
}
g++ でコンパイルされた a.cpp g++.exe -shared c.cpp -o c.dll
#include "interface.h"
#include <iostream>
class 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 メソッドに追加しました。テキストはコンソールに正しく出力されたので、関数呼び出しは間違いなくそれを殺します。
std::cout << "C.DLL Create Class" << std::endl;
COM は、基本的にすべてのクラスが継承されているため (ただし単一のみ)、したがって仮想関数であるため、言語間でもバイナリ互換性をどのように維持するのか疑問に思っていました。基本的な OOP 要素 (つまり、クラスと単一継承) を維持できる限り、オーバーロードされた演算子/関数を使用できなくても、あまり気にしません。