模塊 首先定義下模塊的概念,在C++中可以認為每個二進位文件為一個模塊。比如一個exe可執行程式、一個dll或so動態庫。通常來說一個exe會依賴於幾個dll動態庫。 我們寫一個帶界面的聊天程式,exe為入口主程式 是主模塊,它可能依賴於QtWidgets QtCore等Qt模塊、libevent第 ...
模塊
首先定義下模塊的概念,在C++中可以認為每個二進位文件為一個模塊。比如一個exe可執行程式、一個dll或so動態庫。通常來說一個exe會依賴於幾個dll動態庫。
我們寫一個帶界面的聊天程式,exe為入口主程式 是主模塊,它可能依賴於QtWidgets QtCore等Qt模塊、libevent第三方模塊、我們自己寫的基礎庫xxbase模塊。
介面/跨模塊介面
模塊自己內部調用比較簡單,因為編譯環境和平臺都一致,不存在不相容的問題。如果想把我們的功能提供給其他人使用,就需要導出介面和dll二進位文件了。每種語言有自己的介面定義形式,介面在C或C++里就是一些.h頭文件。頭文件里定義了結構體、函數等,供其他模塊調用。
也可以認為模塊由介面和二進位文件組成。windows編譯出來的dll肯定不能在linux上調用、32位編譯出的dll又不能被64位程式調用、Debug模式和Release模式也存在很多差異。C++不像Java,Java是編譯一次在任意操作系統和平臺都能跑起來。C++呢?不同操作系統、不同CPU、不同系統位數、甚至不同優化參數,編譯出來的二進位文件都不通用。
動態庫
動態庫就是編譯好的、可供其他模塊調用的二進位文件。在windows是dll形式,在類Unix是so形式。
動態庫相比源碼和靜態庫有以下優勢:
- 若以源碼或靜態庫方式提供給別人用,如果後期有一個bug需要修改,那麼所有調用者都需要重新編譯、測試、打包發佈,成本很高。
- 以動態庫方式提供,使用者只需要替換dll或so即可,簡單高效。
動態庫的劣勢:
- 動態庫版本維護比較麻煩,得思考下如何避免“dll地獄”。
跨模塊介面編寫規範
- 跨平臺的介面應該使用C++11新統一的數據類型,比如int32_t int64_t等。因為原始類型在不同平臺編譯器可能位數不同,比如long有的是32位、有的是64位。
- 不能使用STL標準庫里的vector、list等作為函數參數。因為模塊提供者和使用者可能使用不同的C++編譯器,STL實現方式不一樣。
- 只能傳遞裸指針作為函數參數,不能使用智能指針。因為不確定調用者是否支持智能指針、智能指針實現方式是否一樣。
- 介面一經發佈,不允許做任何修改(.h不能改、只允許改.cpp發佈dll更新版本)。因為修改介面後所有使用者都要重新編譯,即使用不到新增的功能。
“介面一經發佈,不允許做任何修改”這聽上去很難,其實是有辦法解決的。我們可以參考COM的思想,提供一個QueryInterface函數,用以查詢所有介面。調用者先判斷這個介面是否存在,存在則調用、不存在則給出錯誤提示。如果後期需要增加新介面,只需要更改下QueryInterface內部實現,就能擴展新介面。
即使把現在所有能想到的功能都抽象成介面,也免不了後期增加新功能。可以提前預留一些欄位、函數,或者設計成方便擴展的形式。