程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Effective C++:條款23:寧以non-member、non-friend替換member函數

Effective C++:條款23:寧以non-member、non-friend替換member函數

編輯:C++入門知識

(一)

有個class來表示網頁浏覽器:

class WebBrowser { 
public: 
    void clearChache(); 
    void clearHistory(); 
    void removeCookies(); 
};

許多用戶會想一整個執行所有這些動作,因此WebBrowser也提供這樣一個函數:clearEverything

class WebBrowser { 
public: 
    void clearChache(); 
    void clearHistory(); 
    void removeCookies(); 
    void clearEverything(); 
};

當然也可以由一個non-member函數調用適當的member函數而提供出來:

void clearBrowser(WebBrowser wb) { 
    wb.clearChache(); 
    wb.clearHistory(); 
    wb.removeCookies(); 
}

那麼哪一個比較好呢?是member函數clearEverything()還是non-member函數claseBrower呢。?

越多東西被封裝,我們改變那些東西的能力也就越大。對象內的數據。越少代碼看到它(訪問它),越多的數據可被封裝,也就越能自由地改變對象數據,例如改變成員變量的數量,類型等等。

所以答案當然是non-member函數claseBrower!因為它導致了較大的封裝性,因為它並不增加“能過訪問class內之private成分”的函數數量。這就解釋了為什麼clearBrowser(一個non_member non-friend函數)比clearEverything(一個member函數)更受歡迎的原因:它導致WebBrowser class有較大的封裝性。

但是這裡有兩件事情要注意下:

第一:這裡只適用於non-member non-friend函數。friend函數對class private成員的訪問權力和member函數相同,因此兩者對封裝的沖擊也相同。
第二:只因在意封裝而讓函數“成為class 的non-member”,並不意味著它“不可以是另一個class的member”。假如我們可以另clearBrowser成為某工具類(utility class)的一個static member函數。

(二)

在C++中,比較自然的做法是讓clearBrowser成為一個non-member函數並且位於WebBrowser所在的同一個namespace(命名空間)內:

namespace WebBrowserStuff{ 
    class WebBrowser{...}; 
    void clearBrowser(WebBrowser wb); 
}

像clearBrowser這樣的函數是個“提供便利的函數”。一個像WebBrowser這樣的class可能擁有大量的便利函數,某些與書簽有關,某些與打印有關,某些與cookie的管理有關…,通常,大多數客戶只對其中某些感興趣。沒有道理一個只對書簽感興趣的客戶卻與一個cookie相關便利函數發生編譯相依關系。分離他們最直接的方法是將他們放入不同的頭文件:

//頭文件webbrowser.h這一頭文件針對class WebBrowser自身以及WebBrowser核心機能。
namespace WebBrowserStuff{ 
    void clearBrowser(WebBrowser wb); 
    ...//WebBrowser核心機能,幾乎所有客戶都需要的non-member函數。 
}

//頭文件“webbrowserbookmarks.h”

namespace WebBrowserStuff{ 
    class WebBrowser{...}; 
    ...//與書簽相關的便利函數 
}

//頭文件“webbrowsercookies.h”

namespace WebBrowserStuff{ 
    class WebBrowser{...}; 
    ...//與cookie相關的便利函數 
}

C++標准程序庫正是這樣的組織方式。數十個頭文件,每個頭文件聲明std的某些機能。如果只想使用vector不用#include ;如果不想使用list也不需要#include .這允許客戶只對他們所用的那一小部分系統形成編譯相依。這種切割機能並不適合class成員函數,因為class 必須整體定義,不能被分割為片段。namespace可以跨越多個源碼文件,而class不能。

將所有便利函數放在多個頭文件中但隸屬同一個命名空間,意味著客戶可以輕松擴展這一組便利函數。他們所要做的就是添加更多non-member non-friend函數到此命名空間內。例如:如果客戶想寫些與影像下載相關的便利函數,只要在WebBrowserStuff命名空間內建立一個頭文件,內含那些函數的聲明即可。新函數就像其他舊函數一樣可用且整合為一體。這是class無法提供的另一個性質,因為class定義對客戶是不能擴展的。



請記住:

盡量用non-member non-friend函數替換member函數。可以增加封裝性、包裹彈性(packaging flexibility)、和機能擴充性。




  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved