Effective C++學習第六天

條款18:讓接口更容易被正確使用,不易被誤用

? ? ? ? ? 設計接口的原則:正確性、高效性、封裝性、維護性、延展性以及協議的一致性;

? ? ? ? ? 設計原則:1)導入新類型來預防很多客戶端的錯誤,多使用系統類型(type system(劃分為多個explicit函數),如果某個變量的可選情況有限,可以通過static函數來替代對象,表示某個特定的對象,并將對象的構造函數定義成private來防止新的對象生成,具體代碼如下:

class? month{

public:

? ? ? ? ? ?static month Jan( ) {return month(1);}//以函數替代對象,來代替某個特定的月份

? ? ? ? ? ...

private:

? ? ? ? ?explicit month(int m);

};

?date(month::Jan( ));//調用

? ? ? ? ? ? 2)限制類型內,什么事情可以做,什么事情不可以做,通常加上限制const;

? ? ? ? ? ? 3)讓你的types的行為和內置types行為一致,提供行為一致的接口;

? ? ? ? ? ? 4)使用智能指針來管理系統資源,可以避免內存泄露(注意智能指針的管理方式和管理條件(單個對象),并用自定義的deleter(資源釋放函數)綁定在智能指針上,deteler(可缺省)),代碼如下:

?std::tr1::shared_ptr<investment>pinv(static_cast<investment*>(0),getridofinvestment);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //shared_ptr第一個參數必須要求是一個指針,一個空指針shared_ptr

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //getridofinvestment為刪除器

這樣的初始化不是最優的:先把pinv初始化為nullptr后對其進行賦值操作(相當于初始化過程是多余的,如果知道初始指針的話,直接用初始指針來初始化pinv才是最優的);

? ? ? ?使用智能指針的另外一個好的特性,它會自動使用它的各一個指針專屬的刪除器,因而消除一個潛在的客戶錯誤(cross-DLL problem),即;對象在動態連接程序庫(DLL)中被new創建,卻在另外一個DLL內被delete,這一類稱為“跨DLL之new/delete成對運用”會導致運行期錯誤,但是智能指針沒有這個問題,它缺省的刪除器來自于智能指針誕生的那個delete;

? ? ? Boost的shared_ptr指針是原始指針(raw pointer)的兩倍大,以動態分配內存作為簿記用途和“刪除器之專屬數據”,以vrtual形式調用刪除器,并以多線程程序修改引用次數時承受線程同步化的額外開銷,但這些額外的執行成本并不顯著,但是在降低客戶錯誤的方面卻起到了很好的效果;

條款19:設計class猶如設計type

? ? ? ? ? ? 在設計一個新的class的時候,就像設計一個新的type,在設計一個高效的class的時候,應該考慮的問題有:

? ? ? ? ? ? ? 1)對象如何被創建和銷毀;

? ? ? ? ? ? ? 2)對象初始化和賦值之間有什么差別;

? ? ? ? ? ? ? 3)新對象在傳值和傳引用方面的考慮;

? ? ? ? ? ? ? 4)對于成員變量引申的成員函數需要進行的錯誤檢查工作及函數拋出異常及異常處理;

? ? ? ? ? ? ? 5)考慮類型的繼承和被繼承情況;

? ? ? ? ? ? ? 6)類型需要做什么樣的轉換,編寫對應的類型轉換函數;

? ? ? ? ? ? ?7)什么函數應該是成員函數,什么不是;

? ? ? ? ? ? ? 8)什么函數應該定義為private;9)成員變量的屬性;

? ? ? ? ? ? ? 9)保證效率、異常安全性以及資源利用(多任務鎖定和動態內存);

? ? ? ? ? ? ?10)一般化你的類型,考慮定義一個模板類;

? ? ? ? ? ? ?11)是否需要定義類,可以在別人類的基礎上添加一個或者多個non-member函數或者template;

條款20:寧以pass-by-reference-to-const替換pass-by-value

? ? ? ? ?缺省情況下C++以by-value方式傳遞對象到函數,函數參數都是以實際實參的副本為初值,而調用端所獲得的也是函數返回值的一個附件,這些副本由對象的copy構造函數產生,使得pass-by-value稱為一個函數操作,如果有很多成員變量的時候;

? ? ? ? ?如果采用傳遞引用的方式,沒有任何的構造函數或者析構函數調用,因為沒有任何的對象被創建;除此之外,以傳引用的方式傳遞參數可以避免slicing(對象切割)的問題,即當一個對derived class對象以by value的方式傳遞并視為一個base class對象,base class的拷貝構造函數被調用,但是derived class區別于base class的部分會被切割掉,而只留下一個base class;

? ? ? ? 避免是slicing(切割)問題的方法,就是采用by-reference-to-const的方式傳遞,原因是因為reference往往是以指針的形式實現,pass by reference通常意味著傳遞的是指針;

? ? ? ?一般而言,對于內置類型、STL的迭代器和函數對象,采用傳值比較方便,其他最好使用傳引用;

條款21:必須返回對象時,別妄想返回其reference

? ? ? ? ? 對于reference只是一個名稱,代表某個既有對象。任何時候看到一個reference聲明式,應該去了解它的另外一個名稱是什么?

? ? ? ? 分析代碼如下:

//返回引用指向棧上的變量

錯誤方法1.const rational& operator*(const rational&lhs,const rational &rhs){

? ? ? ? ?rational result(lhs.n*rhs.n,rhs.d*rhs.d);//試圖返回一個棧空間變量為引用

? ? ? ? ? return result;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//對象在函數調用結束后被銷毀,引用指向一個錯誤的對象;

}

//返回引用指向堆上的變量

錯誤方法2.const rational& operator*(const rational&lhs,const rational &rhs){

? ? ? ? ?rational *result=new rational(lhs.n*rhs.n,rhs.d*rhs.d);//如何對這個new內存進行管理

? ? ? ? ? return *result;? ? ? ? ? ? ?//沒辦法取得reference背后的指針,如何a*b*c時更容易出錯;

}

//返回引用指向一個函數內部的static rational對象

錯誤方法3.const rational& operator*(const rational&lhs,const rational &rhs){

? ? ? ? ?static rational result;? ? //staitc對象會導致多線程安全性

? ? ? ? ?result=rational temp(lhs.n*rhs.n,rhs.d*rhs.d);//static公用問題會帶來錯誤的影響;

? ? ? ? ? return result;? ? ? ? ? ??

}

rational a,b,c,d; if(a*b==c*d)//if里面的數據一直為真,不管其他的怎么取值,因為static原因和返回是引用的原因

正確代碼:inline const rational operator*(const rational&lhs,const rational &rhs){

? ? ? ? ? ??rational result(lhs.n*rhs.n,rhs.d*rhs.d);//雖然會有拷貝構造和析構的成本,但是對于安全性考慮卻是一個很好的做法;

}

結論:不要返回pointer或者reference指向一個local stack對象(見錯誤方法1),或返回一個reference指向一個heap-allocated對象9見錯誤方法2),或返回pointer或reference指向一個local static對象而有可能同時需要多個這樣的對象(見錯誤方法3)

條款22:將成員變量聲明為private

? ? ? ? ? 如果成員變量不是public,客戶能夠訪問對象的方式就是通過成員變量函數,如果public接口內的每樣東西都是函數,那么可以避免客戶在調用class成員時考慮是否需要使用小括號;如果你通過函數訪問成員變量,那么你以后你改變成員變量時,class客戶卻完全不知道class 內部發生了變化;

? ? ? ? 將成員變量隱藏在函數接口的背后沒可以為“所有可能的實現”提供彈性;你對客戶隱藏成員變量(封裝性),你可以確定class的約束條件得到維護,因為只有成員函數可以影響它們;

? ? ? ? 某個東西的封裝性與“當其內容改變時可能造成的代碼破壞量”成反比,改變就是從class中移除它;

? ? ? ?一旦你聲明成員變量為public或者protected時,就很難改變這個成員變量涉及的一切,有太多的代碼需要重寫、重新測試、重新編寫、重新編譯;

? ? ? ?結論:將成員變量聲明為private,這可以賦予客戶訪問數據的一致性、可細微劃分訪問控制、允諾約束條件獲得保證,并為class提供充分的實現彈性;

? ? ? ? ?

? ? ? ? ? ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382390.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382390.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382390.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis運維和開發學習筆記(4) Redis參數意義

Redis運維和開發學習筆記(4) Redis參數意義 文章目錄Redis運維和開發學習筆記(4) Redis參數意義參數意義參數意義 Client連接 問題 id567800790 addr10.18.17.217:37310 fd1572 name age2039114 idle2034860 flagsN db0 sub0 psub0 multi-1 qbuf0 qbuf-free0 obl0 oll0 omem0 …

Effective C++學習第七天

條款23&#xff1a;寧以non-memeber、non-friend替換member函數non-member/non-friend可以給對象帶來更大的封裝性&#xff0c;從兩個方面來考慮&#xff1a;1&#xff09;考慮封裝&#xff0c;越多東西被封裝&#xff0c;它們就越不可見&#xff0c;就越少人看到它&#xff0c…

Redis運維和開發學習筆記(5) 主從復制和sentinel哨兵模式

Redis運維和開發學習筆記(5) 主從復制和sentinel哨兵模式 主從復制 將主節點的數據改變同步給從節點 作用 備份數據讀寫分離 存在的問題&#xff1a; 手動干預切主等操作主節點的寫能力受到單機限制主節點的存儲能力受到單機限制 主從模式的故障恢復 當主節點發生故障時&am…

Effective C++學習第八天

條款26&#xff1a;盡可能延后變量定義式的出現時間當你定義了一個變量&#xff0c;如果在使用變量之前出現異常&#xff0c;那么你得承受一次構造成本和析構成本&#xff0c;而且你沒有使用該變量&#xff1b;本條款給出的建議是延遲變量的定義&#xff0c;直到非得使用該變量…

Redis運維和開發學習筆記(6) 監控Redis工作狀態-info命令

Redis運維和開發學習筆記(6) 監控Redis工作狀態-info命令 文章目錄Redis運維和開發學習筆記(6) 監控Redis工作狀態-info命令info serverinfo clientinfo memoryinfo persistenceinfo statsinfo commandstatsinfo cpuinfo clusterinfo keyspaceinfo server Redis服務器相關的通用…

Effective C++學習第九天

條款32&#xff1a;確定你的public繼承塑模出is-a模型class D&#xff08;derived&#xff09;以public形式繼承class B&#xff08;base&#xff09;&#xff0c;則每一個類型為D的對象同時也是一個類型為B的對象&#xff0c;反之不成立&#xff0c;因此B比D表現出更加一般化的…

Effective C++學習第十天

條款36&#xff1a;絕不重新定義繼承而來的non-virtual函數non-virtual函數執行的是靜態綁定&#xff0c;在編譯器就已經決定&#xff0c;因此對象對用的函數只和指針的類型有關&#xff0c;而與指針所指的對象無關&#xff1b;記住non-virtual函數的性質&#xff1a;不變性凌駕…

Redis運維和開發學習筆記(7) 內存管理和過期策略

Redis運維和開發學習筆記(7) 內存管理和過期策略 文章目錄Redis運維和開發學習筆記(7) 內存管理和過期策略內存回收策略惰性刪除定時任務刪除maxmemory過期策略allkeys-lru主從搭建測試搭建完畢主從測試結果volatile-lru測試結果volatile-ttl測試結果allkeys-lru內存回收策略 …

Effective C++學習第十一天

條款41&#xff1a;了解隱式接口和編譯期多態面向對象編程世界總是以顯式接口&#xff08;源碼可見的接口&#xff09;和運行期多態&#xff08;virtual&#xff09;解決問題&#xff1b;對于templates及泛型編程的世界&#xff0c;隱式接口和編譯期多態顯得更加重要&#xff1…

Redis源碼分析(零)學習路徑筆記

文章目錄第一階段第二階段 熟悉Redis的內存編碼結構第三階段 熟悉Redis數據類型的實現第四階段 熟悉Redis數據庫的實現第五階段 熟悉客戶端和服務器端的代碼實現第六階段 這一階段主要是熟悉Redis多機部分的代碼實現關于測試方面的文件有一些工具類的文件如下SORT命令的實現一些…

Effective C++學習第十二天

條款47&#xff1a;請使用traits classes表現類型信息STL有五類迭代器分類&#xff0c;input迭代器&#xff08;只讀&#xff0c;一次&#xff0c;向前&#xff09;、output迭代器&#xff08;可寫&#xff0c;一次&#xff0c;向前&#xff09;、forward迭代器&#xff08;讀/…

Redis源碼分析(一)redis.c //redis-server.c

Redis源碼分析&#xff08;一&#xff09;redis.c //redis-server.c 入口函數 int main() 4450 int main(int argc, char **argv) {4451 initServerConfig();4452 if (argc 2) {4453 ResetServerSaveParams();4454 loadServerConfig(argv[1]);4455 …

Linux 學習

1.linux文本命令行語言環境設置命令 查看當前語言環境&#xff1a; echo &#xffe5;LANG 修改&#xff1a; LANG選擇的語言環境’ 引申&#xff1a;https://blog.csdn.net/huoyunshen88/article/details/41113633 2.linux中的硬鏈接和軟連接 linux中文件的儲存方式&#xf…

vivo C/C++工程師視頻面試總結 20180802

1.自我介紹&#xff1a;有點兒緊張了&#xff0c;直接把自己簡歷上的一些信息信息說了一遍&#xff0c;說完之后在介紹了一下自己的平時的愛好和興趣&#xff0c;感覺面試官沒有理我&#xff0c;直接進入下一環節了。 2.項目詳情&#xff1a;主要是自己最近的一個項目和自己負…

Redis源碼分析(二)redis-cli.c

文章目錄1. int main()2. parseOptions(int argc, char **argv) 進行ip和port的改變3. lookupCommand(char *name) 查找命令&#xff0c;判斷命令合法3.2 strcasecmp(name,cmdTable[j].name)3.1 redisCommand cmdTable[]4. cliSendCommand(int argc, char **argv)4.1 cliConnec…

C語言中有bool變量嗎?

1.C/C中定義的數據類型&#xff1a; C語言中定義了6種基本數據類型&#xff1a;short,int,long,float,double,char 4種構造類型&#xff1a;數組&#xff0c;結構體&#xff08;struct&#xff09;&#xff0c;共用類型(union)&#xff0c;枚舉類型(enum) 指針類型和空類型 C語…

redis源碼剖析(三)——基礎數據結構

文章目錄SDS鏈表字典這篇文章關于 Redis 的基礎數據:SDS SDS &#xff08;Simple Dynamic String&#xff09;是 Redis 最基礎的數據結構。直譯過來就是”簡單的動態字符串“。Redis 自己實現了一個動態的字符串&#xff0c;而不是直接使用了 C 語言中的字符串。 sds 的數據結…

C++迭代器使用錯誤總結

指針和迭代器的區別&#xff1a; 迭代器&#xff1a; &#xff08;1&#xff09;迭代器不是指針&#xff0c;是類模板&#xff0c;表現的像指針。他只是模擬了指針的一些功能&#xff0c;通過重載了指針的一些操作符&#xff0c;->,*, --等封裝了指針&#xff0c;是一…

redis源碼剖析(四)跳表

文章目錄整數集合跳躍表壓縮列表總結整數集合 當一個集合只包含整數&#xff0c;且這個集合的元素不多的時候&#xff0c;Redis 就會使用整數集合 intset 。首先看 intset 的數據結構&#xff1a; typedef struct intset {// 編碼方式uint32_t encoding;// 集合包含的元素數量…

vivo C/C++工程師 HR視頻面試問題總結20180807

一開始沒想到這次視頻面是HR面試&#xff0c;還以為是技術面試&#xff0c;畢竟上次面試的時候技術問題問的相對比較少&#xff0c;所以面試準備方向有點兒錯了&#xff0c;不過還是總結一下具體問題。 1&#xff09;自我介紹&#xff1a;吸取了上次自我介紹的經驗&#xff0c;…