【Accelerated C++】重点回顾(续)
看了劉未鵬推薦過(guò)的C++入門經(jīng)典《Accelerated C++》,讀此書的過(guò)程中一再感嘆“大師就是大師,他可以很輕松的把東西的本質(zhì)呈現(xiàn)在你面前”,這本書采用了現(xiàn)實(shí)中與我們很接近的學(xué)生成績(jī)信息管理這一例子,層層推進(jìn),一步一步引出C++中的知識(shí)點(diǎn),根據(jù)任務(wù)提出解決方案,讓你感受到C++中一些設(shè)計(jì)的比要性。
一下是我讀此書時(shí)做的筆記,謹(jǐn)用于記憶。
ps:這篇是第二篇,之前的筆記請(qǐng)看這個(gè)鏈接【Accelerated C++】重點(diǎn)回顧。
第八章、編寫泛型函數(shù)
? ? C++語(yǔ)言的一個(gè)重要特性就是可以使用并創(chuàng)建泛型函數(shù)。
2、而且僅有一個(gè)類型以特定的方式支持特定的操作集時(shí),這個(gè)類型才是迭代器。
3、實(shí)現(xiàn)泛型函數(shù)的語(yǔ)言特性叫做‘模板函數(shù)’(template function)
? ? ? --模板是標(biāo)準(zhǔn)庫(kù)的基石。
? ? template <class T>
? ? T median( vector<T> v ){
? ? ? ? ...
? ? }
? ? T為類型參數(shù)。
4、模板實(shí)例化
? ? 當(dāng)我們一個(gè)vector<int>對(duì)象調(diào)用median函數(shù)時(shí),系統(tǒng)會(huì)高效的創(chuàng)建并編譯這個(gè)函數(shù)的一個(gè)實(shí)例,而且在這個(gè)函數(shù)中所有T都會(huì)用int來(lái)取代。
? ? C++標(biāo)準(zhǔn)并沒(méi)有說(shuō)明系統(tǒng)改如何管理模板實(shí)例化,所以每個(gè)系統(tǒng)都按照它自己的特殊方式來(lái)解決實(shí)例化。
? ? 模板實(shí)例化有兩點(diǎn)需要明確的:
? ? ? ? 1)C++系統(tǒng)遵循的是傳統(tǒng)的編輯-編譯-鏈接模板,實(shí)例化往往不是發(fā)生在編譯時(shí)期,就是在鏈接時(shí)期。直到模板實(shí)例化,系統(tǒng)才會(huì)檢驗(yàn)?zāi)0宓拇a是否可用用于指定的類型。
? ? ? ? 2)當(dāng)前的大多數(shù)系統(tǒng)都要求,為了可用實(shí)例化一個(gè)模板,模板的定義,而不僅僅是聲明,都必須是系統(tǒng)可以訪問(wèn)的。這意味著:定義模板的源文件和頭文件都必須是可訪問(wèn)的。很多系統(tǒng)都希望模板的頭文件可以包含源文件 --->函數(shù)聲明與定義都在.h文件中。
5、標(biāo)準(zhǔn)庫(kù)定義了5個(gè)迭代器種類:
? ? 1)順序只讀訪問(wèn) ? ? -->輸入迭代器 ? ? ? ? ? ? ? ? ? ?只能輸入
? ? 2)順序只寫訪問(wèn) ? ? -->輸出迭代器 ? ? ? ? ? ? ? ? ? ?只能輸出
? ? 3)順序讀寫訪問(wèn) ? ? -->前向迭代器(所有標(biāo)準(zhǔn)庫(kù)都滿足),既能輸入,也能輸出
? ? 4)可逆訪問(wèn) ? ? ? ? -->雙向迭代器(容器類都支持) , ? 既能輸入,也能輸出
? ? 5)隨機(jī)訪問(wèn) ? ? ? ? --高效的隨機(jī)訪問(wèn)任意元素, ? ? ? 既能輸入,也能輸出
6、為什么下界常常是指向最后一個(gè)元素的下一個(gè)值? ? ? (更簡(jiǎn)單,可靠)
? ? 1)如果這個(gè)區(qū)間沒(méi)有任何元素,那么就沒(méi)有能標(biāo)記末尾的最后一個(gè)元素。--如果在開(kāi)始元素之前的位置標(biāo)記為空區(qū)間,會(huì)降低程序的可靠性。
? ? 2)可以讓我們只需要比較迭代器的相等性和不等性。
? ? ? ? while( begin != end )
? ? ? ? ? ? ++begin;
? ? 3)可以為我們提供一種罪自然的方式來(lái)表示'區(qū)間之外'。
7、如果沒(méi)有標(biāo)準(zhǔn)庫(kù)需要區(qū)分輸入輸出迭代器和前向迭代器的話,為什么還分出這兩個(gè)種類呢?
? ? 其中的一個(gè)原因是,并不是所有迭代器都與容器相關(guān)聯(lián)。比如:
? ? ? ? 標(biāo)準(zhǔn)庫(kù)提供了可以和輸入輸出流綁定的迭代器。用于istream的迭代器滿足輸入迭代器的要求,用于ostream的迭代器滿足輸出迭代器的要求。
? ? ? ? 使用適當(dāng)?shù)牧鞯?#xff0c;我們可以通過(guò)普通的迭代器操作來(lái)控制一個(gè)istream或者一個(gè)ostream。 流迭代器就是一個(gè)模板。
8、C++標(biāo)準(zhǔn)庫(kù)的一個(gè)重要貢獻(xiàn)就是,通過(guò)把迭代器用作算法和容器之間的粘合劑,算法可以獲得數(shù)據(jù)結(jié)果的獨(dú)立性。此外,算法使用的迭代器都要求支持某些操作,這樣我們就可以根據(jù)這些操作來(lái)分解算法,這就意味著,我們可以很容易的把一個(gè)容器和能夠在這個(gè)容器上使用的算法匹配起來(lái)。
第九章、定義新類型
1、C++有種類型:
? ? 內(nèi)置類型和類。
2、許多C++設(shè)計(jì)都基于這樣的一種思想:
? ? 允許程序員創(chuàng)建于內(nèi)置類型一樣易用的類型。
3、即便一個(gè)程序從來(lái)沒(méi)有直接的創(chuàng)建人和const對(duì)象,它也可能會(huì)通過(guò)調(diào)用創(chuàng)建大量的const對(duì)象的引用。
? ? 如:當(dāng)我面把一個(gè)非const對(duì)象傳遞給帶有一個(gè)const引用的函數(shù)時(shí),這個(gè)函數(shù)就會(huì)把這個(gè)對(duì)象當(dāng)做是const對(duì)象來(lái)處理,編譯器也將只允許它調(diào)用這種對(duì)象的const成員。
4、何時(shí)為成員函數(shù),何時(shí)為非成員函數(shù)?
? ? 有一個(gè)通用的規(guī)則:如果這個(gè)函數(shù)會(huì)改變對(duì)象的狀態(tài),那么這個(gè)函數(shù)就應(yīng)該成為這個(gè)對(duì)象的成員。
5、struct與class的唯一區(qū)別:
? ? 默認(rèn)保護(hù)的方式不同。默認(rèn)保護(hù)會(huì)應(yīng)用于第一個(gè)保護(hù)標(biāo)簽之前的所有成員。
? ? struct:第一個(gè)保護(hù)標(biāo)簽之前的成員都是public
? ? class: 第一個(gè)保護(hù)標(biāo)簽之前的成員都是private
6、訪問(wèn)器函數(shù)
? ? 因?yàn)槲覀冸[藏了數(shù)據(jù)成員,因此我們需要定義一個(gè)訪問(wèn)器函數(shù)來(lái)進(jìn)行訪問(wèn)。
? ? std::string name() const{ return str; }
? ? 那么函數(shù)是一個(gè)const成員函數(shù),它不帶有任何參數(shù),并且返回一個(gè)string值,也就是str的一個(gè)副本。通過(guò)復(fù)制str,而不是返回它的一個(gè)引用。
? ? 這樣的函數(shù)經(jīng)常被允許簡(jiǎn)單地訪問(wèn)隱藏的數(shù)據(jù),這樣就破壞了我們想要得到的封裝性。
? ??
? ? 只有當(dāng)訪問(wèn)器是類的抽象接口的一部分時(shí),才應(yīng)該提供訪問(wèn)器。
? ? 這里,我們抽象出了一個(gè)學(xué)生和一個(gè)對(duì)應(yīng)的最終成績(jī),所以提供一個(gè)name函數(shù)是合適的。換句話說(shuō),我們并沒(méi)有提供其他的成績(jī)--midterm、final、或者h(yuǎn)omework的訪問(wèn)器。因?yàn)檫@些成績(jī)都是時(shí)下的基本組成部分,而不是接口的組成部分。
7、當(dāng)創(chuàng)建標(biāo)準(zhǔn)庫(kù)中某個(gè)類的一個(gè)對(duì)象時(shí),標(biāo)準(zhǔn)庫(kù)可以保證這個(gè)對(duì)象開(kāi)始時(shí)會(huì)有一個(gè)適當(dāng)?shù)闹怠?br />
8、構(gòu)造函數(shù)?
? ? 是特殊的成員函數(shù),它定義了對(duì)象如何初始化。我們沒(méi)有辦法顯示調(diào)用一個(gè)構(gòu)造函數(shù)。但是創(chuàng)建類的一個(gè)對(duì)象時(shí)就會(huì)自動(dòng)的調(diào)用適當(dāng)?shù)臉?gòu)造函數(shù)。
? ? 如果沒(méi)有定義任何夠做函數(shù),編譯器就會(huì)為我們合成一個(gè)。
9、默認(rèn)合成的構(gòu)造函數(shù)的規(guī)則:
? ? 1)如果一個(gè)對(duì)象的類型是定義了一個(gè)或多個(gè)構(gòu)造函數(shù)的類的話,那么適當(dāng)?shù)臉?gòu)造函數(shù)會(huì)完全控制這個(gè)類的對(duì)象的初始化。
? ? 2)如果一個(gè)對(duì)象的類型是內(nèi)置類型的話,那么值初始化會(huì)把它設(shè)置為0,而默認(rèn)初始化會(huì)提供一個(gè)不明確的值。
? ? 3)否則,這個(gè)對(duì)象的類型只能是沒(méi)有定義任何構(gòu)造函數(shù)的類。
? ? ? ? 如果是這樣的話,對(duì)這個(gè)對(duì)象進(jìn)行值初始化或者默認(rèn)初始化就會(huì)對(duì)它的每個(gè)數(shù)據(jù)成員進(jìn)行適當(dāng)?shù)闹党跏蓟蛘吣J(rèn)初始化。如果這個(gè)對(duì)象的任何一個(gè)數(shù)據(jù)成員的類型也是一個(gè)類,而且這個(gè)類帶有自己的構(gòu)造函數(shù)的話,初始化過(guò)程就會(huì)遞歸的進(jìn)行。
10、我們應(yīng)該確保每個(gè)數(shù)據(jù)成員任何時(shí)候都有一個(gè)有意義的值。
11、默認(rèn)構(gòu)造函數(shù):
? ? 不帶有任何參數(shù)的構(gòu)造函數(shù)被認(rèn)為是默認(rèn)構(gòu)造函數(shù)。
? ? 它的工作是確保對(duì)象的數(shù)據(jù)成員被適當(dāng)?shù)爻跏蓟?br />
12、系統(tǒng)在創(chuàng)建一個(gè)新的類對(duì)象時(shí),會(huì)發(fā)生下面幾個(gè)連續(xù)的步驟:
? ? 1)系統(tǒng)會(huì)分配內(nèi)存空間,以保存這個(gè)對(duì)象。
? ? 2)根據(jù)構(gòu)造函數(shù)的初始化列表,初始化這個(gè)對(duì)象。
? ? 3)執(zhí)行構(gòu)造函數(shù)的函數(shù)體。
13、系統(tǒng)會(huì)初始化每個(gè)對(duì)象的每個(gè)數(shù)據(jù)成員。不管夠做函數(shù)初始化列表中是否有這些成員。
? ? 雖然夠做函數(shù)的函數(shù)體隨后可能會(huì)改變這些初始值,但是初始化列表會(huì)在構(gòu)造函數(shù)的函數(shù)體執(zhí)行前執(zhí)行。
? ? 通常來(lái)說(shuō),顯示的為一個(gè)成員提供一個(gè)初始值,要比在構(gòu)造函數(shù)的函數(shù)體中對(duì)這個(gè)成員進(jìn)行賦值要好的多。
? ? ? ? 通過(guò)這樣的初始化,而不是進(jìn)行賦值操作,我們可以避免做兩次相同的工作。
14、對(duì)于內(nèi)置類型的成員來(lái)說(shuō),在構(gòu)造函數(shù)中為它們提供一個(gè)值顯得尤為重要。
? ? 因?yàn)?#xff0c;如果沒(méi)有初始化,那么在局部生存空間中聲明的對(duì)象就會(huì)使用垃圾信息來(lái)初始化。
15、成員初始化的順序取決于它們?cè)陬愔新暶鞯捻樞颉?br /> ? ? 因此,應(yīng)該要避免順序的依賴性--->在構(gòu)造函數(shù)的函數(shù)體中對(duì)這些成員賦值,而不是在構(gòu)造函數(shù)初始化列表中初始化它們。
第十章、管理內(nèi)存和底層數(shù)據(jù)結(jié)構(gòu)
1、理解標(biāo)準(zhǔn)庫(kù)的關(guān)鍵是:
? ? 使用核心語(yǔ)言的編程工具和技巧,這些方法在其他地方也派的上用場(chǎng)。
2、數(shù)組和指針:
? ? 數(shù)據(jù)也是一種容器。
? ? 指針是一種隨機(jī)訪問(wèn)的迭代器。
3、指針是表示對(duì)象的地址的一個(gè)值。每個(gè)不同的對(duì)象都有一個(gè)唯一的地址,這個(gè)地址表示計(jì)算機(jī)中保存這個(gè)對(duì)象的內(nèi)存空間。
? ? 如果x是一個(gè)對(duì)象,那么&x就是它的地址,
? ? 如果p是一個(gè)對(duì)象的地址,那么*p就是對(duì)象本身。
? ? &x中的&是一個(gè)取地址操作符。
? ? *是一個(gè)解引用操作符,作用類似于迭代器上的*的作用。
4、程序員們經(jīng)常使用0值來(lái)初始化指針,因?yàn)?/span>
? ? 可以把0轉(zhuǎn)換為指針時(shí)可以生成一個(gè)值,它可以確保與指向任何對(duì)象的指針的值不同。
? ? 而且,常數(shù)0是唯一一個(gè)可以轉(zhuǎn)換成指針類型的整數(shù)值。
? ? 從0轉(zhuǎn)換生成的值,常常稱為空指針。
5、指向函數(shù)的指針
? ? 沒(méi)有程序可以創(chuàng)建或修改一個(gè)函數(shù),只有編譯器可以做這個(gè)工作。
? ? 對(duì)于函數(shù)來(lái)說(shuō),程序所能做的,僅僅是調(diào)用它或者取得它的地址。
6、int (*fp)(int);
? ? fp是一個(gè)函數(shù)指針,它所指的函數(shù)帶有一個(gè)int類型的參數(shù),并且返回int類型的結(jié)果。
? ? int next( int n )
? ? {
? ? ? ? return n+1; ?
? ? }
? ? 可以使用下列任一條,使fp指向next函數(shù):
? ? ? ? fp = &next;
? ? ? ? fp = next;?
? ? 可以完全這樣的操作:
? ? ? ? i = (*fp)(i);?
? ? ? ? i = fp(i);?
7、
8、數(shù)組:
? ? 不能動(dòng)態(tài)的增長(zhǎng)或收縮,編譯時(shí)期,必須知道數(shù)組匯總的元素個(gè)數(shù)。
? ? 數(shù)組名:就是一個(gè)指向數(shù)組中首元素的指針。
9、字符串直接量
? ? 一個(gè)字符串直接量實(shí)際上是一個(gè)const char數(shù)組,它包含的元素個(gè)數(shù)比字面上的字符數(shù)多1.--‘\0’
? ? 字符串直接量就是一個(gè)指針,指向空字符終止的數(shù)組的首字符。
10、3中內(nèi)存管理
? ? 1)自動(dòng)內(nèi)存管理
? ? ? ? 系統(tǒng)在運(yùn)行時(shí)為這個(gè)局部變量分配所需內(nèi)存,并子退出時(shí)釋放。
? ? ? ? int* invalid_pointer()
? ? ? ? {
? ? ? ? ? ? int x;?
? ? ? ? ? ? return &x; ?
? ? ? ? }
? ? ? ? 這個(gè)函數(shù)會(huì)返回局部變量x的引用,但是,返回時(shí),x所占的內(nèi)存已經(jīng)被釋放。&x創(chuàng)建的指針現(xiàn)在是無(wú)效的。
? ? 2)靜態(tài)內(nèi)存管理
? ? ? ??
? ? ? ? int* pointer_to_static()
? ? ? ? {
? ? ? ? ? ? static int x;?
? ? ? ? ? ? return &x;?
? ? ? ? }
? ? ? ??
? ? ? ? 程序?qū)分配一次內(nèi)存,而且只分配一次,并且只要程序在運(yùn)行,我們就不釋放這個(gè)變量的內(nèi)存。
? ? ? ??
? ? ? ? warnning:每次返回一個(gè)相同的對(duì)象的指針
? ? ? ??
? ? 3)動(dòng)態(tài)分配內(nèi)存
? ? ? ? 刪除一個(gè)零指針沒(méi)有什么影響。
? ? ? ? int *p = new int(42);?
? ? ? ? ++*p; ?//*p is now 43
? ? ? ? delete p;?
? ? ? ? int* pointer_to_dynamic()
? ? ? ? {
? ? ? ? ? ? return new int(0);?
? ? ? ? }
? ? ? ? 調(diào)用這個(gè)函數(shù)的程序應(yīng)該在適當(dāng)?shù)臅r(shí)候負(fù)責(zé)釋放這個(gè)對(duì)象。
第十一章、定義抽象數(shù)據(jù)類型
1、當(dāng)設(shè)計(jì)一個(gè)類時(shí),一般都首先指定需要提供的接口。
2、內(nèi)存分配
? ? 使用new T[n] 不僅會(huì)分配好內(nèi)存空間,還會(huì)調(diào)用T的默認(rèn)構(gòu)造函數(shù)來(lái)初始化每個(gè)元素。
? ? 如果我們使用了new T[n],那么我們就對(duì)T強(qiáng)加了一個(gè)要求:只有當(dāng)T有一個(gè)默認(rèn)構(gòu)造函數(shù)時(shí),用戶才能創(chuàng)建一個(gè)Vec<T>對(duì)象。
3、explicit:
? ? 意思是:只有在用戶明確地調(diào)用這個(gè)構(gòu)造函數(shù)的地方,編譯器才能使用這個(gè)構(gòu)造函數(shù),否則無(wú)法使用。
? ? 這個(gè)關(guān)鍵字只在帶有一個(gè)參數(shù)的構(gòu)造函數(shù)的定義中有意義。
4、通常的,迭代器本身也是類。
5、一般來(lái)說(shuō),操作符函數(shù)可以是成員函數(shù),也可以是非成員函數(shù)。
? ? 然而,索引操作符是必須為成員函數(shù)的操作之一。
6、索引操作符可以找到底層數(shù)組的對(duì)應(yīng)位置,然后返回這個(gè)位置的元素的引用。
? ? 返回引用的原因:
? ? ? ? 如果保持在容器中的對(duì)象很大的話,應(yīng)該避免對(duì)這些對(duì)象進(jìn)行復(fù)制,這樣效率才更高。
7、類的作者可以控制對(duì)戲那個(gè)創(chuàng)建,復(fù)制,賦值以及銷毀過(guò)程中發(fā)生的一切。如果沒(méi)有定義這些操作,編譯器會(huì)合成這些定義。--可能會(huì)導(dǎo)致莫名其妙的行為。
8、復(fù)制構(gòu)造函數(shù)
? ? 無(wú)聊是顯示復(fù)制,還是隱式復(fù)制,都是有一個(gè)叫做復(fù)制構(gòu)造函數(shù)的特殊構(gòu)造函數(shù)來(lái)控制的。
? ? 復(fù)制構(gòu)造函數(shù)是一個(gè)成員函數(shù)。
? ? Vec(const Vec& v);?
? ? 復(fù)制不應(yīng)該改變被復(fù)制的對(duì)象,所以使用const。
7、如果我們復(fù)制指針的值,那么復(fù)制的指針和原先的指針就都指向相同的底層數(shù)據(jù)。
? ? warnning:其中一個(gè)數(shù)值的改變會(huì)引起另一個(gè)值的改變,因?yàn)樗鼈冎赶虻氖峭粋€(gè)數(shù)據(jù)。
? ? 解決方案:當(dāng)復(fù)制一個(gè)Vec對(duì)象時(shí),需要分配新的空間。
8、賦值操作符不同于復(fù)制構(gòu)造函數(shù)的地方是:
? ? 賦值操作符往往需要?jiǎng)h掉左操作符已有的值,然后用新的值,也就是右操作符的值來(lái)替換。
? ??
? ? 需要考慮自我賦值情況的處理。
9、Vec<T>::operator=( const Vec& rhs )
? ? {
? ? ? ? ...
? ? ? ? return *this;?
? ? }
? ? 使用*this:
? ? ? ? this關(guān)鍵字只在成員函數(shù)內(nèi)部有效。
? ? 須確保返回時(shí),引用的對(duì)象仍存在,因此不能返回局部對(duì)象的引用。
10、賦值不是初始化
? ? 理解賦值和初始化之間的區(qū)別是學(xué)好C++的關(guān)鍵之一。
? ? 初始化: 復(fù)制構(gòu)造函數(shù)
? ? 賦值: ? operator=
? ? 區(qū)別:
? ? ? ? 賦值總會(huì)刪除先前的值,而初始化不會(huì)這樣。而且,初始化會(huì)創(chuàng)建一個(gè)新的對(duì)象,同時(shí)為這個(gè)對(duì)象提供一個(gè)值
? ??
? ? 兩者區(qū)別重要的原因:
? ? ? ? 1)構(gòu)造函數(shù)總是用來(lái)控制初始化
? ? ? ? 2)operator=成員函數(shù)總是用來(lái)控制賦值操作
? ? 初始化會(huì)發(fā)生在:
? ? ? ? 1)變量聲明中
? ? ? ? 2)在函數(shù)如果中,傳遞函數(shù)參數(shù)的時(shí)候
? ? ? ? 3)在函數(shù)返回語(yǔ)句中,返回一個(gè)值的時(shí)候
? ? ? ? 4)在構(gòu)造函數(shù)初始化列表中
? ? 賦值發(fā)生在:
? ? ? ? 在表達(dá)式中使用=操作符的時(shí)候
? ??
? ? 如:
? ? ? ? string url_ch = "zerocool"; ? ? ? ? //initialization
? ? ? ? string spaces(url_ch.size(), ''); ? //initialization
? ? ? ? string y; ? ? ? ? ? ? ? ? ? ? ? ? ? //initialization
? ? ? ? y = url_ch; ? ? ? ? ? ? ? ? ? ? ? ? //assignment
11、析構(gòu)函數(shù):無(wú)人和參數(shù)與返回值,控制類的對(duì)象被銷毀時(shí)發(fā)生的操作。
12、良好的習(xí)慣:為每個(gè)類提供一個(gè) 默認(rèn)構(gòu)造函數(shù)(可能是顯式或隱式的提供)
13、如果類的作者沒(méi)有定義賦值構(gòu)造函數(shù)、賦值操作符、析構(gòu)函數(shù)---編譯器會(huì)生成默認(rèn)版。
? ? 默認(rèn)版的函數(shù)會(huì)定義為遞歸操作————根據(jù)元素類型的適當(dāng)規(guī)則、賦值、復(fù)制或者銷毀數(shù)據(jù)元素。
? ? warnning:默認(rèn)析構(gòu)函數(shù)來(lái)銷毀一個(gè)指針時(shí),并不會(huì)釋放指針指向的內(nèi)存空間。
14、三者缺一不可的規(guī)則:
? ? 由于復(fù)制構(gòu)造函數(shù)、析構(gòu)函數(shù)以及賦值操作符如此緊密的聯(lián)系在一起,所以它們之間的關(guān)系就形成了一個(gè)三者缺一不可的規(guī)則:如果一個(gè)類需要一個(gè)析構(gòu)函數(shù),那么它也需要其他兩個(gè)。
15、使用new:不僅會(huì)分配內(nèi)存空間,還會(huì)把這些內(nèi)存初始化(即使我們不適用這些元素)
第十二章、使類的對(duì)象像數(shù)值一樣工作
本章重點(diǎn)討論如何為類設(shè)計(jì)良好的接口。
1、友元
? ? 用來(lái)使非成員函數(shù)讀寫成員數(shù)據(jù)。
? ? 可以定義寫成類定義中的任何地方):不管它是跟在private標(biāo)簽,還是public標(biāo)簽后,都沒(méi)有什么區(qū)別。
? ? 由于友元函數(shù)有特殊的訪問(wèn)權(quán)限,所以它是類的接口的一部分。因此(最好在類定義的開(kāi)頭位置,靠近類的公有接口的地方)
2、定義二元操作符
? ? 非成員函數(shù)-->對(duì)稱性
? ? 把二元操作符定義為非成員函數(shù)就是一個(gè)很好的習(xí)慣。這樣做,我們可以保持操作數(shù)之間的對(duì)稱性。
? ? 如果一個(gè)操作符是一個(gè)類的成員,那么這個(gè)操作符的左操作數(shù)就不能是自動(dòng)類型轉(zhuǎn)換的結(jié)果。
3、explicit
? ? 一般來(lái)說(shuō),如果一個(gè)構(gòu)造函數(shù)是用來(lái)定義對(duì)象的結(jié)構(gòu)的構(gòu)造方式,而不是定義對(duì)象內(nèi)容的構(gòu)造方式的話,這個(gè)構(gòu)造函數(shù)就會(huì)被定義為explicit,、。如果夠做函數(shù)的參數(shù)是對(duì)象的一部分的話,這種構(gòu)造函數(shù)就不應(yīng)該定義為explicit。
4、void*類型
? ? 指向void的指針常常被叫做通用指針,這是因?yàn)檫@種指針可以指向任何類型的對(duì)象。
? ? 當(dāng)然,我們不能對(duì)這種指針解引用,原因是它指向的對(duì)象的類型還是未知的。
? ? 但是我們可以把void*轉(zhuǎn)換為bool類型。
5、類型轉(zhuǎn)換和內(nèi)存管理
? ? 很多C++程序?qū)ο到y(tǒng)的接口都是用C語(yǔ)言或者匯編語(yǔ)言來(lái)完成的,這些語(yǔ)言都是使用以空字符終止的字符數(shù)組來(lái)保存字符串?dāng)?shù)據(jù)的。
6、類型轉(zhuǎn)化是通過(guò)非explicit的夠做函數(shù)定義的,并且這種構(gòu)造函數(shù)只帶有一個(gè)單獨(dú)的參數(shù):類型轉(zhuǎn)換也可以通過(guò)類型轉(zhuǎn)換操作符來(lái)定義,形式為operator type-name()。
第十三、使用繼承和動(dòng)態(tài)綁定
1、繼承是oop的基石。
2、系統(tǒng)是如何創(chuàng)建派生類的對(duì)象,
? ? 系統(tǒng)首先會(huì)為這個(gè)對(duì)象分配空間。接下來(lái),它會(huì)執(zhí)行適當(dāng)類型的構(gòu)造函數(shù)來(lái)初始化這個(gè)對(duì)象。如果這個(gè)對(duì)象是派生類的對(duì)象,就需要給構(gòu)造過(guò)程再加一步,那就是構(gòu)造對(duì)象的基類部分。派生類的對(duì)象是按照下面的方式來(lái)構(gòu)造的:
? ? 1、為整個(gè)對(duì)象分配空間(包括基類成員和派生類成員)
? ? 2、調(diào)用基類的構(gòu)造函數(shù)來(lái)初始化對(duì)象中的基類部分
? ? 3、使用構(gòu)造函數(shù)初始化列表直接初始化派生類的成員
? ? 4、如果派生類的構(gòu)造函數(shù)的函數(shù)體中有語(yǔ)句,就執(zhí)行這些語(yǔ)句
3、多態(tài)和虛函數(shù)
? ? 關(guān)鍵字virtual只能用在類定義中。
? ? ? ? 如果這個(gè)函數(shù)是在聲明之外單獨(dú)定義的話,我們就不需要在定義中重復(fù)關(guān)鍵字virtual了。
4、動(dòng)態(tài)綁定
? ? 虛函數(shù)的運(yùn)行時(shí)選取只與什么時(shí)候通過(guò)引用或者指針來(lái)調(diào)用這個(gè)函數(shù)有關(guān)。
? ? 如果通過(guò)一個(gè)對(duì)象(而不是通過(guò)對(duì)象的引用或者指針)來(lái)調(diào)用一個(gè)虛函數(shù),當(dāng)然可以在編譯時(shí)知道這個(gè)對(duì)象的準(zhǔn)確類型。一個(gè)對(duì)象的類型是確定的:它就是它定義時(shí)的類型,不會(huì)再運(yùn)行時(shí)改變。
? ? 相反,基類的引用或者指針可以引用或指向基類的對(duì)象,也可以引用或指向這個(gè)基類的派生類的對(duì)象,也就是說(shuō),引用和指針的類型以及引用和指針綁定的對(duì)象的類型,在運(yùn)行時(shí)可能會(huì)改變。
5、靜態(tài)綁定:在編譯時(shí)綁定
6、動(dòng)態(tài)綁定和靜態(tài)綁定的區(qū)別是理解C++如何支持OOP的關(guān)鍵。
? ? 如果我們用一個(gè)對(duì)象來(lái)調(diào)用一個(gè)虛函數(shù),這個(gè)調(diào)用就是靜態(tài)綁定,因?yàn)槌司幾g時(shí)期,對(duì)象的類型不可能在執(zhí)行的過(guò)程中發(fā)生變化。
? ? 相反,如果我們通過(guò)一個(gè)指針或者引用來(lái)調(diào)用一個(gè)虛函數(shù),這個(gè)函數(shù)就是動(dòng)態(tài)綁定,也就是說(shuō),是在運(yùn)行時(shí)綁定的。在運(yùn)行時(shí),使用哪個(gè)版本的虛函數(shù),取決于這個(gè)引用和指針綁定的對(duì)象的類型。
7、我們可以在需要指向基類的指針或引用的地方使用派生類類型,這個(gè)例子就是OOP的核心概念————多態(tài)。
? ? 它的意思是,一個(gè)類型可以代表多種類型。
? ? C++是通過(guò)虛函數(shù)的動(dòng)態(tài)綁定特性來(lái)支持多態(tài)的。
8、虛析構(gòu)函數(shù)
? ? 如果一個(gè)指向基類的指針被用來(lái)刪除派生類的對(duì)象時(shí),基類就需要一個(gè)虛析構(gòu)函數(shù)。如果這個(gè)類沒(méi)有別的理由需要一個(gè)析構(gòu)函數(shù)的話,這個(gè)虛析構(gòu)函數(shù)就必須被定義,而且函數(shù)體可以為空。
? ? 虛析構(gòu)函數(shù)也可以繼承。
9、派生類沒(méi)有必要中定義虛函數(shù)。
? ? 如果一個(gè)類沒(méi)有重定義虛函數(shù),它就會(huì)繼承這個(gè)函數(shù)在繼承層次中離當(dāng)前最近的定義。
? ? 然而,首先出現(xiàn)在這個(gè)類中的虛函數(shù)必須被定義。
10、覆蓋
? ? 如果派生類的函數(shù)與基類一樣,就可以覆蓋基類的函數(shù)。
11、友元不能被繼承,也不能傳遞。
from:?http://blog.csdn.net/cyh_24/article/details/8276138
總結(jié)
以上是生活随笔為你收集整理的【Accelerated C++】重点回顾(续)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 关于C# this 指针
- 下一篇: 用Python和OpenCV创建一个图片