青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Shuffy

不斷的學(xué)習(xí),不斷的思考,才能不斷的進(jìn)步.Let's do better together!
posts - 102, comments - 43, trackbacks - 0, articles - 19

[轉(zhuǎn)]http://m.shnenglu.com/tiandejian/archive/2007/05/18/cp_18.html
第四章.
      
設(shè)計規(guī)劃與聲明方式

軟件設(shè)計方案是用來幫助規(guī)劃軟件功能的,通常,它在一開始是一系列優(yōu)秀的思想,但最終都會被具體化,直至其成為可用于開發(fā)的一系列具體接口。之后,這些接口必須轉(zhuǎn)換為 C++ 的聲明。本章中,我們將解決“如何設(shè)計和聲明優(yōu)秀的 C++ 接口”這一問題。我們以下面的建議開始(它可能是設(shè)計接口時要注意的最為重要的一點):接口應(yīng)該易于正確使用,而不宜被誤用。這引出了一系列更為具體的建議,其中我們將討論十分寬泛的議題,包括正確性、效率、封裝、可維護(hù)性、可擴(kuò)展性,還有你需要遵循的慣例。

本章并不期望對于優(yōu)秀接口設(shè)計的建議做到包羅萬象,取而代之的是精選出一部分最為重要的內(nèi)容。各種錯誤和問題對于類 / 函數(shù) / 模板的設(shè)計者來說是家常便飯,本章就是用來時刻警示你遠(yuǎn)離這些常見的錯誤,并為你提供這些問題的解決方法。


 

第18條:     要讓接口易于正確使用,而不易被誤用

C++ 中到處充滿了接口。函數(shù)接口、類接口、模板接口,等等。每個接口都是實現(xiàn)客戶端程序員與你的代碼相交互的一種手段。假設(shè)你的客戶通情達(dá)理,他們的項目也十分優(yōu)秀,他們便會十分看重你的接口是否易于正確使用。這是千真萬確的,如果他們誤用了你的接口中的任一個,那么你也難推其咎。在理想狀態(tài)下,如果客戶端程序員嘗試使用一個接口,但是沒有達(dá)到預(yù)期的效果,那么代碼則不應(yīng)通過編譯。反之,如果代碼通過了編譯,那么則必須要符合客戶端程序員的需求。

開發(fā)中我們應(yīng)做到讓接口更易于正確使用而不易被誤用,這需要你考慮到客戶端程序員會犯的各種錯誤。請參見下邊的示例,假設(shè)你正在編寫一個表示日期時間的類的構(gòu)造函數(shù):

class Date {

public:

 Date(int month, int day, int year);

 ...

};

乍一看,這一接口設(shè)計得很合理(至少在美國很合理),但是當(dāng)客戶端程序員面對這樣的接口時,很容易犯下兩種錯誤。第一,他們可能會使用錯誤的傳參順序:

Date d(30, 3, 1995);            // 啊哦,應(yīng)該是“ 3, 30 ”而不是“ 30, 3

第二,他們可能會傳進(jìn)一個無效的月份或日期:

Date d(3, 40, 1995);            // 啊哦,應(yīng)該是“ 3, 30 ”而不是 “3, 40”

(這一示例看上去有些愚蠢,但是不要忘了,在鍵盤上 4 3 是緊挨著的。這種“擦肩而過”的錯誤在現(xiàn)實中并不少見)

客戶端程序員犯下的許多錯誤是可以通過引入新類型來避免的。實際上,對于防止不合要求的代碼通過編譯,類型系統(tǒng)是你最得力的助手。在上述情況下,我們可以引入幾個簡單的“包裝類型”來區(qū)別日期、月份、和年分,然后再在 Date 構(gòu)造函數(shù)中使用這些類型:

struct Day {

 explicit Day(int d) : val(d) {}

 int val;

};

 

struct Month {

 explicit Month(int m) : val(m) {}

 int val;

};

 

struct Year {

 explicit Year(int y) : val(y) {}

 int val;

};

 

class Date {

public:

 Date(const Month& m, const Day& d, const Year& y);

 ...

};

 

Date d(30, 3, 1995);                   // 報錯!類型錯誤

Date d(Day(30), Month(3), Year(1995));// 報錯!類型錯誤

Date d(Month(3), Day(30), Year(1995));// OK ,類型正確

我們可以改善上邊簡單的應(yīng)用結(jié)構(gòu)體的思路,讓 Day Month Year 變得“羽翼豐滿”,從而可以提供完善的數(shù)據(jù)封裝(參見第 22 條)。但是即使是結(jié)構(gòu)體也足以說服我們:引入新的類型可以十分有效地防止接口誤用的發(fā)生。

只要你在恰當(dāng)?shù)牡胤绞褂昧饲‘?dāng)?shù)念愋停惚憧梢院侠淼叵拗七@些類型的值。比如說,一年有 12 個月,所以 Month 類型應(yīng)該能夠反映出這一點。一個途徑是使用枚舉類型來表示月份,但是枚舉類型并不總能達(dá)到我們對于安全的需求。比如說,枚舉類型可以像 int 一樣使用(參見第 2 條)。一個更安全的解決方法是:預(yù)先定義好所有有效 Month 的集合:

class Month {

public:

 static Month Jan() { return Month(1); }   // 用來返回所有有效月份值

 static Month Feb() { return Month(2); }   // 的函數(shù);

 ...                                    // 下面你將看出為什么使用

 static Month Dec() { return Month(12); } // 函數(shù),而不是對象

 

 ...                                     // 其他成員函數(shù)

 

private:

 explicit Month(int m);                  // 防止創(chuàng)建新的月份值

 ...                                     // 與月份相關(guān)的數(shù)據(jù)

};

 

Date d(Month::Mar(), Day(30), Year(1995));

如果上面代碼中使用函數(shù)來代替具體月份的思路讓你感到奇怪,那么可能是由于你已經(jīng)忘記了聲明非局部靜態(tài)對象可能會帶來可靠性問題。第 4 條可以喚醒你的記憶。

為防止客戶端程序員犯下類似的錯誤,我們還可以采用另一個途徑,那就是嚴(yán)格限制一個類型可以做的事情。加強(qiáng)限制的一個常用的手段就是添加 const 。比如說,第 3 條中曾解釋過,對于用戶自定義類型 operator* 的返回值來說,具備怎樣程度的 const 特性就可以防止客戶端程序員犯下下面的錯誤:

if (a * b = c) ...              // 啊哦,本來是想進(jìn)行一次比較!

實際上,這僅僅是“讓接口易于正確使用,而不易被誤用”的另一種一般的做法:除非有更好的理由阻止你這樣做,否則你應(yīng)該保證你創(chuàng)建的類型的行為與內(nèi)建數(shù)據(jù)類型保持一致。客戶端程序員已經(jīng)清楚 int 的行為,所以只要是合情合理,你就應(yīng)該力求使你的類擁有與 int 一致的行為。比如說,如 a b int 類型,那么為 a*b 值就是不合法的。所以除非你有好的理由拒絕這一規(guī)定,否則你自己創(chuàng)建的類型也應(yīng)該將這一行為界定為不合法。當(dāng)你舉棋不定時,就讓你的類型做與 int 一樣的事情。

設(shè)計接口時應(yīng)防止與內(nèi)建數(shù)據(jù)類型發(fā)生不必要的不兼容性,這樣做的真正目的是讓各類接口擁有一致的行為。除了一致性,很少有特征可以讓接口更加易于正確使用,同時,除了不一致性,也很少有特征可以讓接口變得更加糟糕。 STL 容器的接口大體上(但并不完美)是一致的,這就使得它們更易于使用。比如說每個 STL 容器都有一個名為 size 成員函數(shù),它可以告訴我們這一容器中容納了多少對象。這一點與 Java .NET 是不同的, Java 中使用 length 屬性 來表示數(shù)組的長度, length 方法 來表示字符串的長度,以及 size 方法來表示 List 的大小。而 .NET 中的 Array 擁有一個叫做 Length 的屬性,而 ArrayList 中功能相類似的屬性則叫做 Count 。一些開發(fā)人員認(rèn)為,集成開發(fā)環(huán)境( IDE )的存在讓這類不一致性問題變得不那么重要,但是實際上他們大錯特錯了。不一致性問題會會給開發(fā)人員帶來無窮盡的煩惱,而 IDE 是絕不能解決這些問題的。

任何接口都需要客戶端程序員記憶一些易發(fā)生錯誤的內(nèi)容,這是因為客戶端程序員可能會把這些東西搞砸。比如說,第 13 條中曾引入一個工廠函數(shù)來返回一個指向 Investment 層中動態(tài)分配對象的指針:

Investment* createInvestment();// 來自第 13 章,為簡化代碼省略參數(shù)表

為防止資源泄漏,由 createInvestment 返回的指針在最后必須被刪除,但是這將會給客戶端程序員留下至少兩個犯錯誤的機(jī)會:忘記刪除指針、多于一次刪除統(tǒng)一指針。

13 條中介紹了客戶端程序員如何將 createInvestment 的返回值保存在諸如 auto_ptr tr1::shared_ptr 這樣的智能指針中,然后讓智能指針擔(dān)負(fù)起調(diào)用 delete 的責(zé)任。但是如果客戶端程序員忘記了使用智能指針,這該怎么辦呢?通常情況下,更好的接口的設(shè)計方案是:讓工廠函數(shù)返回一個智能指針,在一開始就不給問題任何發(fā)生的機(jī)會。

std::tr1::shared_ptr<Investment> createInvestment();

這樣便可以從根本上強(qiáng)制客戶端程序員將返回值存儲在一個 tr1::shared_ptr 中,在一個原始 Invesement 對象再有用之后,這樣做可以防止你忘記刪除這一無用的對象。

事實上,返回 tr1::shared_ptr 讓接口設(shè)計人員能夠防止由資源釋放所造成的客戶端錯誤,這是因為 tr1::shared_ptr 允許在智能指針創(chuàng)建時,將資源釋放函數(shù)(一個“刪除器”)綁定在這一智能指針中,而 auto_ptr 沒有這一功能。(參見第 14 條)

假設(shè)一個客戶端程序員從一個 createInvestment 中得到了一個 Investment* 指針,他可能會將這個指針傳給一個名為 getRidOfInvestment 的函數(shù),而不是將其刪除。這樣的接口將會為客戶端程序員帶來新的錯誤,客戶端程序員將會使用錯誤的資源析構(gòu)機(jī)制(也就是使用了 delete 而不是 getRidOfInvestment )。實現(xiàn) createInvestment 的程序員可以通過返回一個綁定了 getRidOfInvestment “刪除器”的 tr1::shared_ptr 來預(yù)防此類錯誤。

tr1::shared_ptr 提供了一個擁有兩個參數(shù)的構(gòu)造函數(shù):需要管理的指針,以及當(dāng)引用計數(shù)值為零時需要調(diào)用的刪除器。關(guān)于創(chuàng)建綁定 getRidOfInvestment “刪除器”的 tr1::shared_ptr ,請看下面的方法:

std::tr1::shared_ptr<Investment> pInv(0, getRidOfInvestment);

                                // 嘗試創(chuàng)建一個 null shared_ptr

                                // 并且讓其包含一個自定義的刪除器;

                                // 這樣的代碼無法通過編譯

這并不是合法的 C++ 語法。 tr1::shared_ptr 的構(gòu)造函數(shù)的第一個參數(shù)必須是一個指針,而 0 則不是,它是一個 int 值。的確,它可以轉(zhuǎn)換成一個指針,但是這種情況下此類轉(zhuǎn)換并不值得推薦, tr1::shared_ptr 的第一個參數(shù)必須是一個實際的指針。通過一次轉(zhuǎn)型可以解決這一問題:

std::tr1::shared_ptr<Investment>

 pInv(static_cast<Investment*>(0), getRidOfInvestment);

                                // 創(chuàng)建一個 null shared_ptr

                                // 并且讓其包含一個自定義的刪除器;

                                // static_cast 的更多信息參見第 27

上面的代碼意味著,在實現(xiàn) createInvestment 時,可讓其返回一個“綁定了 getRidOfInvestment 刪除器的 tr1::shared_ptr ”:

std::tr1::shared_ptr<Investment> createInvestment()

{

 std::tr1::shared_ptr<Investment>

    retVal(static_cast<Investment*>(0),  getRidOfInvestment);

 

 retVal = ... ;                 // retVal 指向恰當(dāng)?shù)膶ο?/span>

 return retVal;

}

當(dāng)然,如果在創(chuàng)建 pInv 之前就確定了其所管理的裸指針,那么將裸指針傳遞給 pInv 的構(gòu)造函數(shù)更理想些,而不應(yīng)該將 pInv 初始化為空值然后對其賦值。為什么這樣?請參見第 26 條。

使用 tr1::shared_ptr 的另一個較為顯著的好處在于:它自動為每個指針預(yù)留一個刪除器,用它們來排除另一類客戶端錯誤,也就是所謂的“跨 DLL 問題”。這一問題在下面的情況中會發(fā)生:一個動態(tài)鏈接庫( DLL )中使用 new 創(chuàng)建了一個對象,而這個對象在另一個 DLL 中由 delete 語句刪除了。在許多平臺上,此類跨 DLL 的“ new/delete 對”將導(dǎo)致運行時錯誤。 tr1::shared_ptr 可以防止此類問題發(fā)生,因為如果創(chuàng)建了一個 tr1::shared_ptr ,它的默認(rèn)刪除器在同一個 DLL 中使用 delete 。舉例說,這將意味著如果 Stock 繼承自 Investment ,同時 createInvestment 是這樣實現(xiàn)的:

std::tr1::shared_ptr<Investment> createInvestment()

{

 return std::tr1::shared_ptr<Investment>(new Stock);

}

那么返回的 tr1::shared_ptr 將在各 DLL 文件中自由穿梭,而不用考慮跨 DLL 問題。這一指向 Stock tr1::shared_ptr 會始終追蹤這一事件:當(dāng) Stock 的引用計數(shù)值為零時,需要使用哪一個 DLL delete 語句。

本條目講解的主要內(nèi)容是如何讓接口更加易于正確使用,而不易被誤用,而不是 tr1::shared_ptr ,但是 tr1::shared_ptr 對于避免此類客戶端錯誤卻是一個不可多得的好工具,使用它是值得的。 tr1::shared_ptr 最為通用的實現(xiàn)來自 Boost (參見第 55 條)。 Boost 中的 shared_ptr 有兩個裸指針那么大,它為記錄和刪除專用數(shù)據(jù)使用動態(tài)分配內(nèi)存,當(dāng)調(diào)用函數(shù)的刪除器時使用虛函數(shù),如果它認(rèn)為一個應(yīng)用程序是多線程的,那么當(dāng)修改該程序的一個引用計數(shù)值時,將引入線程同步的開銷。(你也可以通過定義一個預(yù)處理記號來禁用多線程。) Boost 中的 shared_ptr 也是有缺點的:它比裸指針更大,更慢,而且使用輔助的動態(tài)內(nèi)存。在許多應(yīng)用程序中,這些額外的運行時開銷并不那么顯著,但是它可以降低客戶端程序員出錯的可能,這一點對每個人來說都是十分顯著的。

牢記在心

優(yōu)秀的接口應(yīng)該易于正確使用,而不易誤用。對所有的接口都應(yīng)該力爭做到這一點。

保持與內(nèi)置數(shù)據(jù)類型有一致的行為,是使接口易于正確使用的一種可行的方法

防止錯誤發(fā)生的方法有:創(chuàng)建新的數(shù)據(jù)類型,嚴(yán)格限定類型的操作,約束對象的值,不要將管理資源的任務(wù)留給客戶端程序員。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产一区二区三区在线观看网站| 欧美区视频在线观看| 久久xxxx| 国产精品免费视频xxxx| 中日韩美女免费视频网址在线观看 | 中国成人在线视频| 亚洲欧美韩国| 久久精品一区二区三区不卡牛牛 | 国产精品自拍一区| 国产色视频一区| 9色精品在线| 欧美高清在线| 亚洲欧美国产视频| 国产亚洲欧美激情| 亚欧美中日韩视频| 久久久久久久综合狠狠综合| 亚洲高清激情| 久久―日本道色综合久久| 亚洲欧美国内爽妇网| 国产精品久久一区主播| 欧美一区二区性| 久久精品国产清自在天天线| 亚洲电影一级黄| 久久这里只有精品视频首页| 极品少妇一区二区| 宅男精品视频| 一区二区视频免费在线观看 | 亚洲午夜一级| 国产精品99久久不卡二区| 午夜欧美精品久久久久久久| 欧美人与性禽动交情品| 红桃视频欧美| 国产嫩草一区二区三区在线观看| 久久精品国产第一区二区三区最新章节 | 亚洲精品欧美| 免费日韩av| 亚洲国产合集| 9色国产精品| 欧美日本高清一区| 欧美久久久久久久| 亚洲欧洲在线一区| 久久影院午夜论| 久久夜色精品国产欧美乱| 一区二区日韩| 久久精品99| 国产精品亚洲一区二区三区在线| 欧美精品色一区二区三区| 欧美日韩精品欧美日韩精品 | 欧美福利网址| 久久久久久**毛片大全| 久久久精品久久久久| 欧美顶级大胆免费视频| 影音先锋另类| 亚洲视频1区2区| 国产精品毛片| 久久福利毛片| 亚洲欧美色婷婷| 亚洲激情成人| 嫩草成人www欧美| 一区二区三区我不卡| 国内精品美女在线观看| 亚洲国产一区二区三区a毛片| 日韩视频免费观看高清完整版| 日韩图片一区| 狼人社综合社区| 亚洲国产天堂网精品网站| 午夜精品久久久久久久白皮肤| 亚洲综合999| 99riav1国产精品视频| 午夜精品在线视频| 亚洲欧洲一区| 欧美大片免费| 亚洲免费精彩视频| 免费看亚洲片| 亚洲一区二区在线免费观看视频| 欧美一区二区观看视频| 一区二区三区自拍| 国产婷婷一区二区| 999亚洲国产精| 午夜精品一区二区三区电影天堂| 亚洲国产精品成人一区二区 | 欧美va亚洲va日韩∨a综合色| 国产精品一二三视频| 久久青草久久| 亚洲国产毛片完整版| 国产精品久久久爽爽爽麻豆色哟哟| 亚洲最新视频在线| 国产欧美日韩亚州综合| 亚洲欧美日韩中文在线制服| 一区二区三区国产在线观看| 国产伦精品一区二区三区视频孕妇| 久久久www成人免费无遮挡大片| 亚洲精品美女| 亚洲人成在线观看网站高清| 一区二区久久| 亚洲小少妇裸体bbw| 午夜在线精品偷拍| 久久精品主播| 欧美aa国产视频| 在线一区二区三区四区五区| 黄色小说综合网站| 91久久极品少妇xxxxⅹ软件| 亚洲裸体俱乐部裸体舞表演av| 国产自产女人91一区在线观看| 狠狠色狠色综合曰曰| 国际精品欧美精品| 亚洲国产婷婷香蕉久久久久久99| 国产亚洲va综合人人澡精品| 亚洲欧美国产不卡| 国产精品国产自产拍高清av王其| 99国内精品久久久久久久软件| 亚洲人成在线观看网站高清| 欧美一区日本一区韩国一区| 久久久久久久91| 国产亚洲精品一区二区| 久久综合99re88久久爱| 国产色视频一区| 蜜臀av性久久久久蜜臀aⅴ四虎| 亚洲一二三区在线| 狠狠色丁香婷婷综合| 另类av导航| 99精品视频免费在线观看| 欧美精品在线视频观看| 欧美日一区二区三区在线观看国产免| 欧美日韩亚洲激情| 影音先锋久久久| 一区免费视频| 久久久综合网站| 久久精品电影| 亚洲素人在线| 久久免费黄色| 欧美在线国产| 亚洲高清av在线| 欧美精品久久99久久在免费线| 欧美与黑人午夜性猛交久久久| 久久久久久网站| 性欧美8khd高清极品| 欧美高清免费| 欧美精品在线观看| 欧美日韩免费观看中文| 国产色产综合产在线视频| 亚洲精品久久嫩草网站秘色 | 欧美一级黄色录像| 一二三区精品福利视频| 欧美日韩一二三区| 欧美在线免费视频| 亚洲一级在线观看| 国产精品vvv| 久久国产色av| 性欧美xxxx大乳国产app| 久久久久久久网站| 亚洲青色在线| 亚洲男女毛片无遮挡| 黄色综合网站| 久久狠狠亚洲综合| 国产精品a级| 亚洲国产精品一区二区第四页av | 国内一区二区在线视频观看| 亚洲欧美日韩另类| 亚洲在线观看免费| 亚洲韩国青草视频| 久久国内精品自在自线400部| 亚洲激情在线播放| 亚洲在线网站| 亚洲乱亚洲高清| 欧美精品aa| 久久超碰97人人做人人爱| 欧美日韩国产一级片| 欧美成人官网二区| 亚洲第一视频网站| 欧美一区91| 免费成人在线观看视频| 国产日韩欧美视频| 亚洲一区在线播放| 在线亚洲一区二区| 国产精品v欧美精品v日本精品动漫| 久久综合网hezyo| 精品99一区二区| 久久婷婷国产综合尤物精品| 久久久久久一区二区| 国产精品美女久久久久久2018| 亚洲高清网站| 亚洲风情亚aⅴ在线发布| 日韩一级大片在线| 久久精品亚洲国产奇米99| 国产精品你懂的在线| 亚洲天堂偷拍| 国产精品99久久久久久久女警 | 男人插女人欧美| 亚洲国产日韩一区二区| 91久久国产精品91久久性色| 99成人免费视频| 欧美在线视频观看免费网站| 国产综合第一页| 欧美无乱码久久久免费午夜一区| 亚洲自拍电影| 免播放器亚洲一区| 亚洲一区在线免费| 在线观看欧美一区| 欧美精品免费看|