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

首頁 > 編程 > C++ > 正文

Effective C++學習筆記

2019-11-06 06:44:02
字體:
來源:轉載
供稿:網友

總結: 囫圇吞棗地看完了EffectiveC++這本書,收獲不少。收獲主要是以下幾個方面:

編程注意細節 提高程序效率的細節比如constis-a 和 has-a的區別pure-virtual、impure-virtual和non-virtual之間繼承該如何處理繼承中隱藏基類的成員等設計方法 什么時候該繼承(is-a),什么時候該以對象作為data member(is-inplemented-in-terms-of);Template method、 Strategy, 抽象工廠等設計模式泛型編程與模板編程異常安全性 異常處理copy-swap技術

由于沒有太多的實戰經歷,所以有些東西并不是很懂。 所幸在看書過程中,做過一些筆記整理,其中 大部分內容摘抄自書上,一小部分加上自己的一點點理解,方便日后回顧。

02: 對于單純常量,最好以const對象或 enums 替換#define

03: 盡可能使用const

mutable 關鍵字表征 const成員函數可以修改mutable成員

04: 為內置對象進行手工初始化,C++并不保證初始化他們;

05: 在類中,如果有引用 或const對象,記得要自己編寫構造函數,拷貝構造函數等,因為編譯器自己生成的相關函數很大可能達不到要求。

06: 為了駁回編譯器自動提供的功能(構造函數,拷貝等),可以將相應的member function declared PRivate,并且不予實現; 或者使用像Uncopyable這樣的base class;

07: 當類作為基類的時候,有可能表現出多態的時候,應將虛構函數設計成virtual

09: 絕不在構造函數和析構函數中調用virtual function; 如果在base class 調用了virtual function,在派生類的構造函數初始化基類的時候,實際上還是調用的是base class的function,并沒有調用dervied class的內容(此時derived class 并沒有完成初始化)

10: 令 Operator= 返回一個referece to *this (方便連續賦值 如 a = b = c;);

11: 在operator=中處理“自我賦值”copy and swap 技術實現自我賦值;

class Widgt {void swap(Widgt& rhs);// 交換*this 和 rhs的數據}Widget& Widget::operator=(const Widget& rhs) { Widget tmp(rhs); swap(rhs); return *this;}

12: 復制對象的時候務必記住每一個成員 copying函數應該確保復制“對象內的所有成員變量” 以及“所有base Class 的成分”

13: 以對象管理資源 記得用智能指針管理資源;

14: 在資源管理類中心小心copying行為

當資源管理類需要copy的時候 需要從以下幾個方面考慮 禁止復制(將拷貝構造函數,以及拷貝賦值函數 設置于private有點類似于unique_ptr<>)對底層資源使用“引用計數法” 模仿“shared_ptr”復制底部資源(深拷貝,每一份對象都有自己的heap內存)轉移資源的管理權(有點像 auto_ptr )

15: 資源管理類中需要提供對原始資源的訪問

智能指針類可以隱式轉化為底部的原始指針,便于訪問底部的成員可以有顯式轉換(較為安全)和隱式轉換(對客戶比較安全)

16: 成對使用new 和delete 尤其注意在利用typedef中聲明新的類型名時(盡量少用typedef聲明數組類型)

17: 以獨立語句將new出來的對象置入智能指針

Design and Declarations

18: make interfaces easy to use correctly and hard to use incorrectly 令自己的types和內置types的行為一致 盡量保持接口一致性 如STL容器的接口 19: Treat class design as type design type的對象應該如何該創建和銷毀;對象的初始化和賦值該有什么樣的區別新type的對象如果pass by value 意味著什么新type的合法值 ?哪些賦值是合法的是否需要配合某個繼承圖系(inheritance graph)嗎?什么樣的類型轉換?什么樣的操作符和函數對此新type而言是合理的?(設計接口)什么樣的標準函數應該被駁回?(設計為private)誰該取用新type的成員? (設計為public)20: 以pass-by-reference to const 替換pass-by-value 前者比較高效,同時可以避免切割問題;對于內置類型、STL的迭代器和函數對象。 對他們而言,pass-by-value往往比較合適21: Don’t try to return a reference when you must return an object; 絕對不要返回pointer或reference指向一個local stack對象(會產生未定義的行為)絕對不要返回指向一個heap-allocated對象(無法控制對象的銷毀)絕對不要返回pointer或reference指向一個local static對象(可能需要多個這樣的對象)(在多線程情況下也難以保證安全)22: Declare data members private 可以實現對data member的各種權限控制有利于封裝,注意protected 并不比public更具有封裝性23: Prefer non-member non-friend替換member函數 其實是具有更大的封裝性(注意namespace)增加封裝性,packaging flexibility 和機能擴充性24: 若所有參數需要類型轉換,請將此函數設計成non-member函數 有理數類(Rational)的的四則運算; Rational tmp = Rational() * 2 ; Rational tmp = 2 * Rational(); 考慮這兩種情況

25 : Consider support for a non-throwing swap( 不拋異常)

缺省版本swap

如果缺省版本的效率不夠,可以嘗試做

提供一個public swap函數(這個函數,不要拋出異常)在class 或template所在的命名空間內提供一個non-member swap,并調用上述的swap成員函數如果正編寫一個class(非template),需要特化std::swap, 并令他調用你的成員swap

注意: 不要忘std里加入任何新的東西

// default swaptemplate <typename T>void swap(T& a, T& b){ T temp(a); a = b; b = tmp;}class Widget { public: void swap(Widget &other);}26: 盡可能延后變量定義式的出現的時間(用到的時候才再去聲明) 循環里用到的變量盡量在循環里聲明,除非 賦值成本比構造加析構低,處理代碼中效率高度敏感的部分

27: 盡量少做轉型動作(如果轉型必要,就封裝在函數里面)(新式轉型 好于 舊式轉型)

const_castdynamic_caststatic_cast reinterpret_cast 不適合移植

28: Avoid returning “handles”to object internals

handles (pointer, reference, iterators)

29: Strive for exception safety code(為異常安全性努力是值得的)

帶有異常安全性的函數會: 不泄露任何資源不允許數據敗壞

異常安全函數(Exception-safe code)提供下面三個保證之一

基本承諾

程序內的任何事物都保持在有效狀態下(對象或者數據結構不會有因此而損壞)當異常時,可以選用默認狀態,也可以回復到變換之前的狀態

強烈保證(往往以copy-and-swap實現出來)

函數成功,就完全成功,如果失敗,程序會回復到調用函數之前的狀態nothrow 保證

30: Understand the ins and outs of inlining

virtual 和inline同時出現,編譯器往往會拒絕inlineinline限制在小型、頻繁調用的函數身上構造函數最好不要inline

31: 將文件間的編譯依存關系降至最低

接口與實現的分離 如果使用object reference 或者 object pointers可以完成任務,就不要使用objects如果能夠,盡量以class聲明式替換定義式為聲明式和定義式提供不同的頭文件

32: 確定public繼承是is-a的關系(注意區分has-a)

適用于derived class身上的所有事情都能適用于base class身上

33: Avoid hiding inherited names(避免隱藏繼承的成員名)

避免隱藏基類的成員名 可以使用using 聲明式或者 forwarding function

34: Differentiate between inheritance of interface and inheritance of implementation(區分接口繼承和實現繼承)

pure virtual: 為了讓derived class繼承函數接口(繼承了的具象類都要重新聲明)impure virtual: 繼承該函數的接口和缺省實現non-virtual:為了令derived classes繼承函數的接口及一份強制性實現

35: 考慮virtual函數以外的其他設計方式(提及設計模式中的Template Method 和 Strategy)

令客戶通過public non-virtual成員函數間接調用private函數(NVI手法)/// Template Methodclass GameCharacter {public: int healthValue() const { ··· // 做一些事前工作 int retVal = doHealthValue(); ··· //做一些事后工作 return value; } ···private: virtual int doHealthValue() const { ··· // 缺省算法,計算健康指數 } }借由function pointers實現strategy模式class GameCharacter;int defaultHealthCalc(const GameCharacter& gc);class GameCharacter {public: typedef std::function<int (const GameCharacter&)> HealthCalcFunc; explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf) {} int healthValue() const { return healthFunc(*this);}private: HealthCalcFunc healthFunc;};/// 可以轉換成function對象short calcHealth(const GameCharacter&); // 返回類型 non-intstruct HealthCalculator { //為計算健康值設計的函數對象 int operator()(const GameCharacter&) const {···}};class GameLevel {public: float health(const GameCharacter&) const; // 成員函數 ···};使用non-virtual interface手法,那是Template Method設計模式的一種特殊形式,它以public non-virtual成員函數包裹性較低訪問性(private或protected)的virtual函數將virtual函數替換為“函數指針成員變量”,這是strategy設計模式的一種分解表現形式以function成員變量替換virtual函數, 因此允許使用任何可以轉變成(callable entity)function對象的表達式,也是strategy的一種表現形式

36: Never redefine an inherited non-virtual function.

如果重新定義從基類繼承的non-virtual function, 那么就應該是設計出現了問題

37: 絕不重新定義繼承而來的缺省參數值(針對virtual函數)

virtual函數系動態綁定,而缺省參數值卻是靜態綁定如果需要缺省值,應該將該函數設計為non-virtual函數,再設計一個private的virtual function 如同前面介紹的Template Method設計

38: Model “has-a”or “is-implementated-in-terms-of” through composition

在應用域內,是has-a的關系在實現域中,是根據某物實現出 例如STL庫中的stack是以vector為底層數據結構實現的

39: 明智而謹慎地使用private繼承

private繼承某種意義上說 is-implemented-in-terms-of, 所以盡可能使用38條中使用復合的方式實現除非確定private繼承可以造成empty base最優化

40: 明智而謹慎地使用多重繼承

多重繼承比單一繼承復雜;以及可能會對virtual繼承的需要virtual繼承會增加大小,速度,初始化復雜度等成本

模板與泛型編程

41: 了解隱式接口和編譯器多態

以不同的template參數具現化function templates會導致調用不同的函數,這就是編譯期多態(有點像重載函數) classes 和 templates都支持接口(interface)和多態(polymorphism)對classes而言接口是顯式的,以函數簽名為中心。多態則是通過virtual函數發生于運行期對template參數而言,接口是隱式(implicit)的,奠基于有效表達式;多態則是通過template具現化發生于編譯期

42: 了解typename的雙重意義

聲明template參數時,class和typename可以互換記得使用typename標識嵌套從屬類型名稱;但不要在base class List或 member initialization list內以它作為base class的修飾符

43: 學習處理模板化基類內的名稱

繼承模板基類的時候,基類的成員函數不可見;這個時候可以用一下三種方式解決 在前面添加this指針利用using語句,使模板基類的函數可見利用基類的類名加::調用基類函數

44: 將與參數無關的代碼抽離template

template生成多個classes和多個function,所以任何template代碼都不該與某個造成膨脹(怎么造成代碼膨脹呢?)的template參數產生相依關系因非類型模板參數而造成的代碼膨脹,往往可以消除,做法是以函數參數或class成員變量替換template參數因類型參數(type parameters)而造成的代碼膨脹,往往可以降低,做法是讓帶有王權相同的二進制表述的instantiation types共享實現碼

45: 運用成員函數模板接受所有的兼容類型

請使用member function templates生成“可接受所有兼容類型”的函數如果你聲明member templates 用于“泛化copy構造”或泛化assignment操作,還是需要聲明正常的拷貝構造函數和copy assignment操作符46: 需要類型轉換時請為模板定義非成員函數 編寫class template,需要支持與此template相關函數 支持參數之隱式類型轉換 時,請將那些函數定義為 class template內部的friend函數

47: 請使用traits classes表現類型信息

Trait classes使得“類型相關信息”在編譯器可以用,以template特化實現整合overloading技術

48: 認識template元編程

49: 了解new-handler的行為

new-handler函數要完成以下的事情:

讓更多內存可被使用安裝另一個new-handler(令new-handler修改會影響new-handler行為的static數據,global數據)卸除new-handler(將null指針傳遞給set_new_handler)跑出bad_alloc(或派生出來的)異常

Nothrow new是一個頗為局限的工具,因為它只適用于內存分配 夠來的構造函數還是可能跑出異常

50: 了解new和delete的合理替換時機

51: 編寫new和delete時需要固守常規

52: 寫了placement new也要寫placement delete(不熟悉)

53: pay attention to compiler warnings

編譯器的警告能力是不一樣的; 編寫程序,爭取完全無警告

54: 讓自己熟悉TR1在內的標準程序庫(現在C++11基本都實現了)

55: 讓自己熟悉boost程序庫(泛型編程, 模板元編程)

沒有理解和不太懂的地方,也有幾處,主要集中于:

泛型編程模板元編程trait type、trait class, 特化以及偏特化

接下來的學習之路也需要偏重以下上述方面。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 巴青县| 弥渡县| 二连浩特市| 肥乡县| 晋州市| 东光县| 曲水县| 宁远县| 澎湖县| 周口市| 墨脱县| 前郭尔| 汽车| 内江市| 铜梁县| 沙河市| 同江市| 南华县| 乐山市| 高邑县| 云阳县| 宝应县| 合阳县| 酒泉市| 西平县| 察隅县| 宝坻区| 名山县| 榆社县| 霍山县| 宣城市| 来安县| 台山市| 永川市| 塔城市| 贵州省| 志丹县| 格尔木市| 合肥市| 海安县| 施甸县|