前言
相信很多使用C++語言的人都有這麼一種錯誤的觀點 - 除了主函式,其他函式都應當宣告為某個類的成員函式,以實現封裝性。
這種觀點錯在哪裡?我們又該如何在成員函式與非成員函式之間進行選擇呢?
針對這個問題,本文將給出一種非常科學的解決方案。
問題分析
假定有一個網頁瀏覽器類,其中有用來清除快取,清除瀏覽記錄,清除cookies的成員函式:
1 class WebBrowser 2 { 3 public: 4 // ...... 5 void clearCache(); // 清除快取 6 void clearHistory(); // 清除瀏覽記錄 7 void removeCookies(); // 清除cookies 8 // ...... 9 };
相信有很多使用者希望能夠一次執行完所有的這些函式。
故也許你會做出這樣的設計:
1 class WebBrowser 2 { 3 public: 4 // ...... 5 void clearEverything(); // 這個函式包含下面三個函式 6 void clearCache(); // 清除快取 7 void clearHistory(); // 清除瀏覽記錄 8 void removeCookies(); // 清除cookies 9 // ...... 10 };
但更有經驗的程式設計師會用非成員函式實現此功能:
1 // 非成員函式 2 void clearBrowser(WebBrowser & wb) 3 { 4 wb.clearCache(); 5 wb.clearHistory(); 6 wb.removeCookies(); 7 }
下面來分析這兩種做法:
某個功能用成員函式來實現的話,物件中的變數將對該函式徹底開放,同時會將物件中的資料更大程度的暴露出來,尤其是隨著開發的進行你會設定非常非常多的成員函式,到時你都搞不清哪些資料是封閉的哪些是可供使用者操縱的。
故這樣的做法很大程度上其實是破壞了封裝性,應當採用下面這種做法。
也許你會抱怨,如果設定為非成員函式,那到時一堆非成員函式,程式碼豈非亂成一團?
那麼你就需要好好學習下 - C++中非成員函式的使用方法了。
C++中非成員函式的使用方法
還是接著上面這個例子。
隨著開發的進展,這個瀏覽器的類中會增加與書籤有關的操作,與cookies相關的操作。。。。。。這種情況下,科學的做法是:
1. 瀏覽器類中僅僅包含最核心的一部分函式 - 也即所有的使用者都需要的。
2. 對於書籤與cookies相關操作,分別建立各自的.h,.cpp檔案。
3. 將1,2中的所有標頭檔案都囊括進一個namespace。這裡設定namespace的目的就是為了防止非成員函式重名。關於namespace的相關說明請查閱相關文件。
具體實現可參考以下程式碼:
1 // webbrowser.h 2 namespace WebBrowserStuff { 3 4 class WebBrowser 5 { 6 // ...... 7 // 僅定義該類最核心的功能 8 // ...... 9 }; 10 11 // 定義核心非成員函式 12 } 13 14 // webbrowserbookmarks.h 15 namespace WebBrowserStuff { 16 17 // 定義與書籤有關的非成員函式 18 19 } 20 21 // webbrowsercookies.h 22 namespace WebBrowserStuff { 23 24 // 定義與cookies有關的非成員函式 25 26 }
對於類的使用者來說,需要哪方面功能就 #include 哪個標頭檔案,非常方便。
小結
如今一些大型類庫,比如標準類庫,OpenCV,都是這樣的組成及使用方式。
以後的文章中會告訴你如何將你自己實現的模組封裝成dll,供其他人使用,就像OpenCV OpenGL等知名類庫一樣,敬請期待:)