国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

C++箴言:用非成員非友元函數取代成員函數

2019-11-17 05:29:12
字體:
來源:轉載
供稿:網友

  想象一個象征 web 瀏覽器的類。在大量的函數中,這樣一個類也許會提供清空已下載成分的緩存。清空已訪問 URLs 的歷史,以及從系統移除所有 cookies 的功能:

class WebBrowser {
 public:
  ...
  void clearCache();
  void clearHistory();
  void removeCookies();
  ...
};
  很多用戶希望能一起執行全部這些動作,所以 WebBrowser 可能也會提供一個函數去這樣做:

class WebBrowser {
 public:
  ...
  void clearEverything(); // calls clearCache, clearHistory,
  // and removeCookies
  ...
};
  當然,這個功能也能通過非成員函數調用適當的成員函數來提供:

void clearBrowser(WebBrowser& wb)
{
 wb.clearCache();
 wb.clearHistory();
 wb.removeCookies();
}
  那么哪個更好呢,成員函數 clearEverything 還是非成員函數 clearBrowser?

  面性對象原則指出:數據和對它們進行操作的函數應該被綁定到一起,而且建議成員函數是更好的選擇。不幸的是,這個建議是不正確的。它產生于對面向對象是什么的一個誤解。面向對象原則指出數據應該盡可能被封裝。與直覺不同,成員函數 clearEverything 居然會造成比非成員函數 clearBrowser 更差的封裝性。此外,提供非成員函數答應 WebBrowser 相關功能的更大的包裝彈性,而且,可以獲得更少的編譯依靠和 WebBrowser 擴展性的增進。因而,在很多方面非成員方法比一個成員函數更好。理解它的原因是非常重要的。

  我們將從封裝開始。假如某物被封裝,它被從視線中隱藏。越多的東西被封裝,就越少有東西能看見它。越少有東西能看見它,我們改變它的彈性就越大,因為我們的改變僅僅直接影響那些能看見我們變了什么的東西。某物的封裝性越強,那么我們改變它的能力就越強。這就是將封裝的價值評價為第一的原因:它為我們提供一種改變事情的彈性,而僅僅影響有限的客戶。

  結合一個對象考慮數據。越少有代碼能看到數據(也就是說,訪問它),數據封裝性就越強,我們改變對象的數據的特性的自由也就越大,比如,數據成員的數量,它們的類型,等等。作為多少代碼能看到一塊數據的粗糙的尺度,我們可以計數能訪問那塊數據的函數的數量:越多函數能訪問它,數據的封裝性就越弱。

  數據成員應該是 PRivate 的,因為假如它們不是,就有無限量的函數能訪問它們。它們根本就沒有封裝。對于 private 數據成員,能訪問他們的函數的數量就是類的成員函數的數量加上友元函數的數量,因為只有成員和友元能訪問 private 成員。假設在一個成員函數(能訪問的不只是一個類的 private 數據,還有 private 函數,枚舉,typedefs,等等)和一個提供同樣功能的非成員非友元函數(不能訪問上述那些東西)之間有一個選擇,能獲得更強封裝性的選擇是非成員非友元函數,因為它不會增加能訪問類的 private 部分的函數的數量。這就解釋了為什么 clearBrowser(非成員非友元函數)比 clearEverything(成員函數)更可?。核転?WebBrowser 獲得更強的封裝性。

  在這一點,有兩件事值得注重。首先,這個論證只適用于非成員非友元函數。友元能像成員函數一樣訪問一個類的 private 成員,因此同樣影響封裝。從封裝的觀點看,選擇不是在成員和非成員函數之間,而是在成員函數和非成員非友元函數之間。(當然,封裝并不是僅有的觀點,假如觀點來自隱式類型轉換,選擇就是在成員和非成員函數之間。)

  需要注重的第二件事是,假如僅僅是為了關注封裝,則可以指出,一個函數是一個類的非成員并不意味著它不可以是另一個類的成員。這對于習慣了所有函數必須屬于類的語言(例如,Eiffel,java,C#,等等)的程序員是一個適度的安慰。例如,我們可以使 clearBrowser 成為一個 utility 類的 static 成員函數。只要它不是 WebBrowser 的一部分(或友元),它就不會影響 WebBrowser 的 private 成員的封裝。

  在 C++ 中,一個更自然的方法是使 clearBrowser 成為與 WebBrowser 在同一個 namespace(名字空間)中的非成員函數:

namespace WebBrowserStuff {
 class WebBrowser { ... };
 void clearBrowser(WebBrowser& wb);
 ...
}
  相對于形式上的自然,這樣更適用于它。無論如何,因為名字空間(不像類)能展開到多個源文件中。這是很重要的,因為類似 clearBrowser 的函數是方便性函數。作為既不是成員也不是友元,他們沒有對 WebBrowser 進行專門的訪問,所以他們不能提供任何一種 WebBrowser 的客戶不能通過其它方法得到的功能。例如,假如 clearBrowser 不存在,客戶可以直接調用 clearCache,clearHistory 和 removeCookies 本身。

  一個類似 WebBrowser 的類可以有大量的方便性函數,一些是書簽相關的,另一些打印相關的,還有一些是 cookie 治理相關的,等等。作為一個一般的慣例,多數客戶僅對這些方便性函數的集合中的一些感愛好。沒有理由讓一個只對書簽相關的方便性函數感愛好的客戶在編譯時依靠其它函數,例如,cookie 相關的方便性函數。分隔它們的直截了當的方法就是在一個頭文件中聲明書簽相關的方便性函數,在另一個不同的頭文件中聲明 cookie 相關的方便性函數,在第三個頭文件聲明打印相關的方便性函數,等等:


// header "webbrowser.h" - header for class WebBrowser itself
// as well as "core" WebBrowser-related functionality
namespace WebBrowserStuff {

 class WebBrowser { ... };
 ... // "core" related functionality, e.g.
 // non-member functions almost
 // all clients need
}
// header "webbrowserbookmarks.h"
namespace WebBrowserStuff {
... // bookmark-related convenience
} // functions
// header "webbrowsercookies.h"
namespace WebBrowserStuff {
 ... // cookie-related convenience
} // functions

...
  注重這里就像標準 C++ 庫組織得一樣嚴密。勝于有一個單獨的一體式的 <C++StandardLibrary> 頭文件包含 std namespace 中的所有東西,它們在許多頭文件中(例如,<vector>,<algorithm>,<memory>,等等),每一個都聲明了 std 中的一些機能。僅僅需要 vector 相關機能的客戶不需要 #include <memory>,不用 list 的客戶沒有必要 #include <list>。這就答應客戶在編譯時僅僅依靠他們實際使用的那部分系統。當機能來自一個類的成員函數時,用這種方法分割它是不可能的,因為一個類必須作為一個整體來定義,它不能四分五裂。

  將所有方便性函數放入多個頭文件中——但是在一個 namespace 中——也意味著客戶能輕易地擴充方便性函數的集合。他們必須做的全部就是在 namespace 中加入更多的非成員非友元函數。例如,假如一個 WebBrowser 的客戶決定寫一個關于下載圖像的方便性函數,他或她僅僅需要新建一個頭文件,包含那些函數在 WebBrowserStuff namespace 中的聲明。這個新的函數現在就像其它方便性函數一樣可用并被集成。這是類不能提供的另一個特性,因為類定義對于客戶是擴充封閉的。當然,客戶可以派生新類,但是派生類不能訪問基類中被封裝的(也就是說,private 的)成員,所以這樣的“擴充機能”只有二等身份。此外,不是所有的類都是作為基類設計的。

  Things to Remember

  ·用非成員非友元函數取代成員函數。這樣做可以提高封裝性,包裝彈性,和機能擴充性。

上一篇:在 C++中處理錯誤

下一篇:再談CMOS密碼

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 溧水县| 阜宁县| 宜宾市| 浪卡子县| 诸城市| 成都市| 夹江县| 万全县| 五华县| 隆子县| 莱州市| 赤壁市| 包头市| 崇州市| 吉林省| 正安县| 固始县| 阿拉善右旗| 进贤县| 凤冈县| 岳普湖县| 深州市| 溆浦县| 察隅县| 中宁县| 永春县| 东乌珠穆沁旗| 甘洛县| 马尔康县| 蒲城县| 大丰市| 乌恰县| 靖边县| 赫章县| 喀喇沁旗| 仁化县| 景东| 穆棱市| 竹溪县| 瑞昌市| 长宁区|