2012-12-15 42 views
0

我覺得這個問題可能有一個簡單的解決方案,這對我來說並不明顯 - 我有一個配置類,用於存儲從ini文件加載的各種配置選項等。在我的應用程序中,我有一個庫和客戶端,以及2個配置 - 將庫構建爲DLL並使客戶端動態鏈接,或將它們作爲單個二進制構建在一起。那麼如何在庫和客戶端中使用/使用我的配置對象呢?如果我在兩者中都包含配置類定義,我認爲它會因重新定義而給我提供鏈接錯誤。如何設計一個配置工具既可以靜態鏈接也可以動態鏈接?

回答

0

如果我在兩者中都包含配置類定義,我認爲它會因重新定義而給我提供鏈接錯誤。

不,它不會。 Windows DLL不尊重一個定義規則。基本上,在Windows中,ODR在模塊邊界處停止,即ODR在內可執行,而內但不在它們之間。這是不是一件好事是不相關的,就是這樣。所以,你可以在DLL和可執行文件中包含你的配置類的定義。但是,將會有兩個獨立的單例實例(因爲我認爲它是單例類,正如配置類通常那樣),每個模塊都有一個實例。從這個意義上講,它不會是一個真正的單身人士,至少,不是跨模塊。

如果你想要一個真正的模塊單身人士,你將不得不做更多的工作。您有兩種選擇:主從或合併(或「菊花鏈」)。

第一個選項是指定一個模塊(例如,可執行文件)作爲實例化(並保留)單例對象的模塊,然後將指向該實例的指針傳遞給所有「從」模塊,然後通過一個通用接口使用它(因此兩個模塊對於配置類都有相同的聲明,但只有一個模塊創建它並將其傳遞給其他模塊)。這將是這個樣子:

在頭文件 「config_class.h」:

class ConfigClass { 

    // a bunch of declarations... 

    public: 
    static ConfigClass& getInstance(); // the access-point for the singleton. 
}; 

#ifdef MY_LIB_NOW_BUILDING_MASTER 

extern "C" __declspec(dllimport) void setConfigClassInstance(ConfigClass* pobj); 

#else 

extern "C" __declspec(dllexport) void setConfigClassInstance(ConfigClass* pobj); 

#endif 

在cpp文件 「config_class.cpp」:

#include "config_class.h" 

// a bunch of definitions for the config_class member functions. 

#ifdef MY_LIB_NOW_BUILDING_MASTER 

ConfigClass& ConfigClass::getInstance() { 
    static ConfigClass instance(/* */); 
    return instance; 
}; 

#else 

static ConfigClass* masterInstance; 

void setConfigClassInstance(ConfigClass* pobj) { 
    masterInstance = pobj; 
}; 

ConfigClass& ConfigClass::getInstance() { 
    return *masterInstance; 
}; 

#endif 

,其中,在上述例如,您可以從主模塊(很可能是主可執行文件)中調用setConfigClassInstance來爲DLL設置配置對象,但要確保DLL在靜態初始化(加載)期間不需要配置類。

第二個選擇是合併或菊花鏈你的單身人士。在這種情況下,每個模塊創建自己的單例實例,然後使用與上面類似的方案,將指針傳遞給彼此的實例,從而將它們合併爲一個實例(交叉鏈接),或者將它們鏈接在一起(例如,像循環鏈表或環形列表),並將呼叫分派給相應的實例。

我認爲對於您的應用程序,第一個選項可能是最簡單的。

N.B .:在非Windows環境下,情況完全不同,以上都不適用。

+0

「如果我在兩者中都包含配置類定義,我認爲它會因重新定義而給我提供鏈接錯誤。」語句是用於靜態鏈接(將dll構建爲a。lib),而不是動態的;我相信你用上面提供的解決方案,同樣會發生。我相信我可以通過預處理器定義的豐富多彩的使用來解決這個問題,但是如果可能的話,我試圖避免使用特定的方法。 – Rollie

+0

@Rollie哦,所以,如果我得到這個權利,讓我們說你有:main.cpp(應用程序代碼),lib.cpp(庫代碼)和config.cpp(配置類代碼)。其中編譯成main.o,lib.o和config.o。然後你建立一個「exe + dll」爲「(main.o,config.o)+(lib.o,config.o)」的版本,然後你想把dll變成一個靜態庫,並且天真地嘗試鏈接(main.o,config.o,lib.o,config.o)並獲得ODR錯誤。解決方案很簡單,只是在構建靜態版本時不要多次鏈接配置代碼。而已。 –