泛型和面向對象C++
1. 在類內部定義的函數默覺得inline,內聯函數應該在頭文件裏定義,由於其定義對編譯器必須是可見的,以便編譯器可以在調用點內聯展開該函數的代碼。
此時,僅有函數原型是不夠的。
2.assert
3.異常
4.因為流對象不能復制。因此不能存儲在容器中;因為流不能復制。因此形參或返回類型也不能為流類型,必須用指針或引用。對IO對象的讀寫會改變它的狀態,因此引用必須是非const的。
5.假設須要重用文件流讀寫多個文件,必須在讀還有一個文件之前調用clear清除該流的狀態。
6.前向聲明。
在聲明之後。定義之前。類是一個不全然類型。即已知它是一個類型,但不知道包括哪些成員。
不全然類型僅僅能以有限方式使用。
不能定義該類型的對象。不全然類型僅僅能用於定義指向該類型的指針和引用,或者用於聲明(而不是定義)使用該類型作為形參類型或返回類型的函數。
在創建類的對象之前。必須完整地定義該類。必須定義類,而不僅僅是聲明類,這樣,編譯器就會給類的對象預定對應的存儲空間。相同地,在使用引用或指針範文類的成員之前,必須定義類。
7.不能從const成員函數返回指向類對象的普通引用。const成員函數僅僅能返回*this作為一個const引用。
8.引用全局變量
int height; void dummy(int height) { ::height = 1; }函數中設定全局變量height為1而不是參數height為1.
9.必須對不論什麽const或引用類型成員以及沒有默認構造函數的類類型的不論什麽成員使用初始化式。
10.依照與成員聲明一致的次序編寫構造函數初始化列表是個好主意。此外,盡可能避免使用成員來初始化其它成員。
11.實際上,假設定義了其它構造函數,則提供一個默認構造函數差點兒總是對的。通常在默認構造函數中給成員提供的初始值應該指出該對象時“空”的。
12.友元不是授予友元關系的那個類的成員,所以它們不受其聲明出現部分的訪問控制影響。通常。將友元聲明成組地放在類定義的開始或結尾是個好主意。友元能夠是普通的非成員函數,或前面定義的其它類的成員函數。或整個類。
13.static函數沒有this指針,不是不論什麽對象的組成部分,不能聲明為const。不能聲明為虛函數。
14.static數據成員必須在類定義體的外部定義
15.拷貝構造函數可用於初始化順序容器中的元素,如
vector<string> svec(5);編譯器首先使用string默認構造函數創建一個暫時值來初始化svec,然後使用拷貝構造函數將暫時值拷貝到svec的每一個元素。
16.為了防止復制,類必須顯式聲明其拷貝構造函數為private。假設想要連友元和成員的復制也禁止。就能夠聲明一個private拷貝構造函數但不正確其定義。這樣在鏈接時導致錯誤。
17.不同意復制的類對象僅僅能作為引用傳遞給函數或從函數返回。它們也不能用作容器的元素。
18.容器中的元素總是依照逆序撤銷,先撤銷下標為size()-1的元素。最後是下標為0的元素。
19.三法則:指的是假設須要析構函數,則也須要賦值操作符和拷貝構造函數。
20。合成析構函數並不刪除指針成員所指向的對象。
21.析構函數沒有返回值,沒有形參。由於不能指定不論什麽形參,所以不能重載析構函數。盡管一個類能夠定義多個構造函數,但僅僅能提供一個析構函數。應用於類的全部對象。
22.析構函數與拷貝構造函數或賦值操作符之間的一個重要差別是,即使我們編寫了自己的析構函數,合成析構函數仍然執行。如我們編寫了一個空的析構函數。則類的各成員還能夠被合成析構函數撤銷。
合成析構函數在自己定義析構函數之後執行。
23.大多數C++類採用下面三種方法之中的一個管理指針成員:
(1)指針成員採取常規指針型行為。這種類具有指針的全部缺陷但無需特殊的復制控制。
(2)類可以實現所謂的“智能指針”行為。
指針所指向的對象是共享的。但類可以防止懸垂指針。
(3)類採取值型行為。
指針所指向的對象時唯一的,由每一個類對象獨立管理。
24.不能重載的操作符
:: .* . ?
:
25.重載操作符必須具有至少一個類類型或枚舉類型的操作數。這條規則強制重載操作符不能又一次定義用於內置類型對象的操作符含義。
26.操作符的優先級、結合性或操作數數目不能改變。除了函數調用操作符operator()之外,重載操作符時使用默認實參是非法的。
27.作為類成員的重載函數。形參看起來比操作數少1.作為成員函數的操作符有一個隱含的this形參,限定為第一個操作數。
一般將算術和關系操作符定義為非成員函數,而將賦值操作符定義為成員。
28.重載逗號、取地址、邏輯與、邏輯或等操作符通常不是好做法。這些操作符具有實用的含義,假設我們定義了自己的版本號,就不能使用這些內置含義。
29.當一個重載操作符含義不明顯時。給操作取一個名字更好。對於非常少用的操作,使用命名函數通常比用操作符更好。假設不是普通操作,沒有必要為簡潔而使用操作符。
30.管理容器鍵類型和順序容器的類型應定義==和<操作符,理由是很多算法假定這些操作符存在。比如sort算法使用<操作符。find算法使用==操作符。
31.類定義下標操作符時。一般須要定義兩個版本號:一個為非const成員並返回引用,還有一個為const成員並返回const引用。
32.類型轉換函數必須是成員函數,不能指定返回類型,而且形參表必須為空。盡管轉換函數不能指定返回類型,可是每一個轉換函數必須顯式返回一個指定類型的值。比如,operator int返回一個int值。轉換函數一般不應該改變被轉換的對象。
因此,轉換操作符通常應定義為const成員。
33.類類型轉換之後不能再跟還有一個類類型轉換。假設須要多個類類型轉換,則代碼將出錯。
34.派生類僅僅能通過派生類對象訪問其基類的protected成員。派生類對其基類類型對象的protected成員沒有特殊訪問權限。
35.派生類虛函數調用基類版本號時。必須顯式使用作用域操作符。假設派生類函數忽略了這樣做,則函數調用會在執行時確定而且將是一個自身調用,從而導致無窮遞歸。
36.private繼承時能夠在派生類的public部分使用using Base::XX的形式。使得基類的私有成員能夠被用戶訪問。
37.使用class保留字定義的派生類默認具有private繼承,而用struct保留字定義的類默認具有public繼承。
38.友元關系不能繼承。基類的友元對派生類的成員沒有特殊訪問權限。假設基類被授予友元關系,則僅僅有基類具有特殊訪問權限,該基類的派生類不能訪問授予友元關系的類。
39.假設基類定義了static成員,則整個繼承層次中僅僅有一個這種成員。不管從基類派生出多少個派生類,每一個static成員僅僅有一個實例。
40.構造函數僅僅能初始化其直接基類的原因是每一個類都定義了自己的接口。派生類構造函數不能初始化基類的成員且不應該對其基類成員賦值。
41.與構造函數不同,派生類析構函數不負責撤銷基類對象的成員,編譯器總是顯式調用派生類對象基類部分的析構函數。每一個析構函數僅僅負責清楚自己的成員。
42.即使沒有工作要做。繼承層次的根類也應該定義一個虛析構函數。
43.在復制控制中,僅僅有析構函數能夠定義為虛函數,構造函數不能定義為虛函數。構造函數是在對象全然構造之前執行的。在構造函數執行的時候,對象的動態類型還不完整。將賦值操作符定義為虛函數將在派生類中定義一個參數為基類對象的operator=,與派生類中賦值操作符不符合。因此,將類的賦值操作符定義為虛函數會令人混淆,並且不會有什麽用處。
44.假設在構造函數或析構函數中調用虛函數。則執行的是為構造函數或析構函數自身定義類型的版本號。
45.在繼承情況下,派生類的作用域嵌套在基類作用域中。
46.對象、引用或指針的靜態類型決定了對象可以完畢的行為。甚至當靜態類型和動態類型可能不同的時候。就像使用基類類型的引用或指針時可能發生的,靜態類型仍然決定著可以使用什麽成員。
47.在派生類作用域中派生類成員函數將屏蔽基類成員。即使函數原型不同,基類成員也會被屏蔽。
48.假設派生類想通過自身類型使用全部重載版本號,則派生類必需要麽重定義全部重載版本號,要麽一個也不重定義。
若不想重定義全部,能夠為重載成員提供using聲明。一個using聲明僅僅能指定一個名字。不能指定形參表。因此能夠將該函數的全部重載實例加到派生類的作用域。
49.虛函數必須在基類和派生類中擁有同一原型。
50.C++ primer P501。派生類的同名函數可能會將基類的虛函數屏蔽。進而無法通過派生類對象調用,能夠通過指向派生類對象的基類引用或指針調用。
51.由於派生類對象在賦值給基類對象時會被“切掉”。所以容器與通過繼承相關的類型不能非常好地融合。
52.面向對象編程所依賴的多態性稱為執行時多態性。泛型編程所依賴的多態性稱為編譯時多態性或參數式多態性。
53.用作模板形參的名字不能在模板內部重用,這一限制還意味著模板形參的名字僅僅能在同一模板形參中使用一次。
54.在模板成員名前加上keywordtypename作為前綴,能夠告訴編譯器將成員當作類型。
55.數組形參能夠聲明為數組的引用。假設形參是數組的引用,編譯器不會將數組實參轉化為指針,而是傳遞數組的引用本身。在這樣的情況去,數組大小成為形參和實參類型的一部分。編譯器檢查數組實參的大小與形參的大小是否匹配。
56.顯式模板實參從左至右與相應模板形參相匹配。
57.當編譯器看到模板定義的時候,它不馬上產生代碼。僅僅有在看到用到模板時。如調用了函數模板或調用了類模板的對象的時候,編譯器才產生特定類型的模板實例。
58.在包括編譯模型中。編譯器必須看到用到的全部模板的定義。
59.非類型模板實參必須是編譯時常量表達式。
60.特化和部分特化(偏特化)能夠具有與通用類模板全然不同的成員集合。
61.函數模板能夠重載:能夠定義有同樣名字但形參數目或類型不同的多個函數模板。也能夠定義與函數模板有同樣名字的普通非模板函數。
62.異常對象通過復制被拋出表達式的結果創建,該結果必須是能夠復制的類型。
63.拋出指針一般是個壞主意:拋出指針要求在相應處理代碼存在的隨意地方存在所指向的對象。
64.棧展開期間,釋放局部對象所用的內存並執行類類型局部對象的析構函數。
65.在為某個異常進行棧展開的時候,析構函數假設又拋出自己的未經處理的還有一個異常,將會導致調用標準庫terminate函數。一般而言,terminate函數將調用abort函數,強制從整個程序非正常退出。
66.與析構函數不同,構造函數內部所做的事情常常會拋出異常,因此要保證適當地撤銷已構造的成員。
67.假設找不到匹配的catch,程序就調用庫函數terminate。
68.catch捕獲的類型必須是已定義的,類型的前向聲明不行。
69.通常,假設catch字句處理因繼承而相關的類型的異常,它就應該將自己的形參定義為引用。
70.假設catch(...)與其它catch子句結合使用。它必須是最後一個。否則。不論什麽跟在它後面的catch子句都將不能被匹配。
71.構造函數要處理來自構造函數初始化式的異常,唯一的方法是將構造函數編寫為函數測試塊。
72.異常安全指即使發生異常程序也能正常操作,即被分配的不論什麽資源都適當地釋放。通過定義一個類來封裝資源的分配和釋放,能夠保證釋放資源。這一技術常稱為“資源分配即初始化”,簡稱RAII。
應該設計資源管理類。以便構造函數分配資源而析構函數釋放資源。
73.autoi_ptr僅僅能用於管理從new返回的一個對象。它不能管理動態分配的數組。
當auto_ptr被復制或賦值的時候,有不平常的行為,因此,不能將auto_ptr存儲在標準庫容器類型中。auto_ptr的復制和賦值改變右操作數,因此,賦值的左右操作數必須都是可改動的左值。
74.應該僅僅用get詢問auto_ptr對象或者使用返回的指針值。不能用get作為創建其它auto_ptr對象的實參。
75.auto_ptr對象與內置指針的還有一個差別是,不能直接將一個地址9或者其它指針)賦給auto_ptr對象
76.auto_ptr缺陷:
77.假設一個函數聲明沒有指定異常說明。則該函數能夠拋出隨意類型的異常。
78.在編譯的時候,編譯器不能也不會試圖驗證異常說明。假設函數拋出了沒有在其異常說明中列出的異常,就調用標準庫函數unexpected。
默認情況下,unexpected函數調用terminate函數,terminate函數通常會終止程序。
79.由於不能再編譯時檢查異常說明,異常說明的應用一般是有限的。異常說明實用的一種重要情況是。假設函數能夠保證不會拋出不論什麽異常,對函數的用戶和編譯器都有所幫助。
80.派生類虛函數異常說明必須與相應基類虛函數的異常說明相同嚴格,或者比後者更受限。這個限制保證,當使用指向基類類型的指針調用派生類虛函數的時候,派生類異常說明不會添加新的可拋出異常。
81.在用還有一指針初始化帶異常說明的函數的指針。或者將後者賦值給函數地址的時候。兩個指針的異常說明不必同樣。可是,源指針的異常說明必須至少與目標指針的一樣嚴格。
82.命名空間能夠在全局作用域或其它作用域內部定義。但不能在函數或類內部定義。
命名空間作用域不能以分號結束。
83.命名空間能夠在幾個部分中定義。命名空間由它的分離定義部分的總和構成。命名空間是累積的。
84.未命名的命名空間與其它命名空間不同。未命名的命名空間的定義局部於特定文件,從不跨越多個文本文件。
在命名空間引入C++之前,採用static聲明局部於文件的名字。
85.假設頭文件定義了未命名的命名空間,那麽,在每一個包括該頭文件的文件裏,該命名空間中的名字將定義不同的局部實體。
86.接受類類型形參(或類類型指針及引用形參)的函數(包含重載操作符),以及與類本身定義在同一命名空間中函數(包含重載操作符),在用類類型對象(或類類型的引用及指針)作為實參的時候是可見的。
87.為了提供命名空間中所定義模板的自己的特化。必須保證在包括原始模板定義的命名空間中定義特化。
88.在虛派生中,由最底層派生類的構造函數初始化虛基類。不管虛基類出如今繼承層次中不論什麽地方,總是在構造非虛基類之前構造虛基類。
89.sort、sort_heap排序默認使用less。為遞增排序。make_heap默認使用less,為最大堆。大的在前,小的在後。。
90.模板函數是函數模板的一個實例。
91.函數不能偏特化。
92.除非我有一個好理由同意構造函數被用於隱式類型轉換。否則我會把他聲明為explicit。
93.
Widget w2 = w1; //調用copy構造函數,而非copy assignment運算符
泛型和面向對象C++