標籤:

c++中如何為一個程序寫擴展?

老師交給我們一個任務,給定一個程序(附帶程序代碼的各個介面,但是沒有給完整的源代碼),讓我們為程序寫一下擴展功能(原本的功能是顯示感測器傳出的圖像,現在要對這段圖像進一步處理並保存),這可不可以實現?我們只知道java中寫插件是寫成plugins和features,c++的話是寫成dll文件?如果可以實現大概需要如何實現?需要學習什麼知識?


我簡單的說明下c/c++里的插件系統是怎麼運行的吧。包括.COM、Qt Plugin等各種框架的插件機制,基本都是這樣的原理。

Windows/Linux均支持通過文件名運行時載入動態鏈接庫,通過函數符號名稱獲得函數指針,故:

1、定義純虛基類作為Interface(如果有Java基礎比較好理解)。

2、把實現類封裝為dll文件,用LoadLibrary運行時載入。

3、通過C API獲取插件對象實例。因為C++ ABI在不同編譯器、不同編譯器版本之間有差異,而的C ABI是穩定的。

所以就可以這麼做了——

1、寫一個介面類,內部都是純虛函數,用作定義對外介面

2、寫一個實例類,繼承實現這個介面。這個類不用導出。

3、導出一個C函數getInstance如下

extern "C" std::shared_ptr& getInstance()
{
// for c++17
// return std::dynamic_pointer_cast&(std::make_shared&());
return std::shared_ptr&(dynamic_cast&(new MyImplementClass));
}

4、使用插件者,通過文件名在運行時載入dll

5、使用插件這,通過字元串"getInstance"獲取到函數指針

6、運行函數指針,得到對象實例。然後就可以通過介面調用了

註:

對純虛方法的引用,可以直接編譯通過,不需要鏈接方法實現。

所以使用者只需要include介面描述,就可以在代碼里使用該介面類型的指針對象了,可以順利編譯通過,不需要鏈接。

然後實際運行時,就可以隨意替換實現類,然後通過配置文件或其他手段,通知程序從某個dll插件載入實例即可。

使用者代碼如下:

// 載入dll
HMODULE lib = LoadLibrary("xxx.dll");
// 解析函數指針
std::function&(void)&> getInstanceFunc = GetProcAddress(lib, "getInstance");
// 獲得對象
this-&>myPlugInstance = getInstanceFunc();
// 通過介面隨便操作咯
this-&>myPlugInstance-&>doSomething();

程序退出前別忘了通過FreeLibrary卸載dll庫

Linux下同理,只不過變成了.so庫,同樣有對應的系統API完成這些操作


怎麼感覺就是直接補充源碼的意思


推薦閱讀:

代碼里寫很多if會影響效率嗎?
Facebook 是如何在短時間內做出 「mark safe" 這個功能的?
怎麼證明我們的宇宙不是個程序?
如何寫爬蟲程序爬取豆瓣網或者新浪微博里的內容?
輪子哥的gaclib發展的怎樣?走的時什麼路線?

TAG:編程 | 程序 | C | dll |