簡體   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