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,然後使用拷貝構造函數將臨時值復制到svec的每個元素。svec(5);
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.在模板成員名前加上關鍵字typename作為前綴,可以告訴編譯器將成員當作類型。
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排序默認使用less,為遞增排序。
90.模板函數是函數模板的一個實例。