軟件工程師是程序員嗎電腦優(yōu)化工具
- 面向?qū)ο缶幊痰娜齻€(gè)基本概念:數(shù)據(jù)抽象、繼承和動(dòng)態(tài)綁定(多態(tài)):
- 基類應(yīng)該提供一些類型無(wú)關(guān)的成員函數(shù)定義,將與類相關(guān)的函數(shù)留給不同的派生類定義:
,派生類是通過(guò)類派生列表(
class derivation list
)對(duì)基類進(jìn)行聲明: - 對(duì)于那些與類相關(guān)的成員函數(shù),我們需要在基類中聲明為
virtual
,在派生類用用關(guān)鍵字override
顯式強(qiáng)調(diào)我們要重新定義的成員函數(shù): - 動(dòng)態(tài)綁定(
dynamic binding
,也叫run-time binding
)可以用一份代碼在多個(gè)對(duì)象上執(zhí)行: - 對(duì)于涉及繼承的幾個(gè)類而言,基類的幾個(gè)特征是:1. 對(duì)于類相關(guān)的成員函數(shù)定義成(純)虛函數(shù)。2. 對(duì)于讓派生類訪問(wèn),但用戶無(wú)法訪問(wèn)的成員,用
protected
關(guān)鍵字。3. 基類的析構(gòu)函數(shù)必須為虛函數(shù)。 - 除了
static member
和constructor
,我們都可以聲明為virtual
: - 基類中對(duì)成員的訪問(wèn)控制,影響派生類對(duì)成員的訪問(wèn):
,簡(jiǎn)單講,我們可以將派生類當(dāng)做基類的特殊用戶來(lái)看待。目前將,有三個(gè)用戶:類的實(shí)現(xiàn)者、類的用戶和派生類。
- 對(duì)于派生類而言,需要在(
class derivation list
,類派生列表)指定其基類和打算override來(lái)自基類的成員:。對(duì)于派生列表中用
public
繼承的基類,我們可以正常使用動(dòng)態(tài)綁定
,此外可以將基類的接口作為派生類接口的一部分: - 派生類對(duì)象由多個(gè)部分組成,正因如此,才允許動(dòng)態(tài)綁定。以及
Derived-to-Base
(指針)的轉(zhuǎn)換,注意轉(zhuǎn)換的部分是we can bind a base-class reference or pointer to the base-class part of a derived object.:,即
- 不管是什么類,每個(gè)類都負(fù)責(zé)自己成員的初始化:
,關(guān)于在繼承的情況下,構(gòu)造函數(shù)的執(zhí)行順序是從基類到派生類:
- 派生類可以直接訪問(wèn)基類中
protected
和public
限定的成員,但是要尊重類的接口。此外值得注意的是:派生類的作用域被嵌入在基類作用域的里面: - 對(duì)于
static
成員,它們不屬于對(duì)象,所以它們自始至終只有一份代碼: - 通過(guò)
final
關(guān)鍵字防止該類被繼承: - 派生類(指針)到基類(指針)的轉(zhuǎn)換是理解C++中OOP的重中之重:
- 在繼承場(chǎng)景下,基類的指針和引用的靜態(tài)類型和動(dòng)態(tài)類型可能會(huì)不同:
,對(duì)于變量或表達(dá)式的靜態(tài)類型在編譯時(shí)確定,而動(dòng)態(tài)類型是其在內(nèi)存中表示的類型,在運(yùn)行時(shí)確定。
- 因?yàn)榕缮惖交惖霓D(zhuǎn)換是因?yàn)榛惖闹羔?引用可以綁定到派生類的基類部分。但是基類作為一個(gè)獨(dú)立的對(duì)象時(shí),它可能不存在派生類的成員,所以不存在基類到派生類的隱式轉(zhuǎn)換:
- 派生類到基類的隱式轉(zhuǎn)換的前提是用基類的指針/引用,派生類與基類的對(duì)象之間是無(wú)法轉(zhuǎn)換的:
,強(qiáng)制將派生類轉(zhuǎn)換成基類時(shí)就會(huì)發(fā)生sliced down:
- 繼承層次下的
virtual
function必須要定義,因?yàn)槠涫欠袷褂弥荒茉谶\(yùn)行時(shí)確定: dynamic binding
happens only when a virtual function is called through a pointer or a reference of base class:,對(duì)于其他對(duì)象類型在編譯時(shí)確定的情況下,調(diào)用的成員函數(shù)就是確定的:
,dynamic binding引出C++的polymorphism:
- 如果一個(gè)成員函數(shù)在base class是virtual,那么它在后續(xù)的派生類中也是隱式的virtual,此外派生類override基類的虛函數(shù)時(shí),需要保證參數(shù)列表一致:
- 在派生類中,覆蓋相應(yīng)的虛函數(shù)時(shí),可以使用
override
關(guān)鍵字通知編譯器來(lái)檢查派生類中重定義時(shí)是否與基類中的參數(shù)列表相同:,也可以聲明成員函數(shù)為
final
來(lái)防止該函數(shù)被override
。 - 我們也可以使用作用域操作符來(lái)規(guī)避動(dòng)態(tài)綁定機(jī)制:
- 純虛函數(shù)通常是一個(gè)通用的概念,負(fù)責(zé)規(guī)定函數(shù)簽名,實(shí)現(xiàn)細(xì)節(jié)由具體的派生類決定:
,如果非要定義純虛函數(shù),我們只能在類外進(jìn)行。
- 抽象基類不能定義對(duì)象,不過(guò)應(yīng)該可以定義指針/引用:
- 每個(gè)類都負(fù)責(zé)自身成員的初始化,這里要注意在繼承框架下,構(gòu)造函數(shù)的調(diào)用順序:
- 每個(gè)類也控制它的成員是否允許被“用戶(類的使用者/派生類)”訪問(wèn):
- 從派生類訪問(wèn)基類基礎(chǔ)來(lái)的成員受兩個(gè)方面影響:該成員在基類內(nèi)的訪問(wèn)聲明符,在派生類的派生列表中的訪問(wèn)聲明符:
- 派生類到基類的隱式轉(zhuǎn)換需要條件:
- 類的三個(gè)使用者:類的實(shí)現(xiàn)者、類的用戶和派生類:
friendship
不可被傳遞和繼承:- 關(guān)鍵字
struct
和class
的默認(rèn)訪問(wèn)聲明符和默認(rèn)派生訪問(wèn)聲明符不同: - 派生類的作用域是嵌入到基類里面:
- 編譯時(shí)的靜態(tài)類型確定某個(gè)成員函數(shù)是否可以被調(diào)用,因?yàn)槊樵兪菑撵o態(tài)類型所在的類開始,然后向基類搜索的:
- 如果派生類具有與基類的同名成員名稱,因?yàn)榕缮惖淖饔糜蚴乔度朐诨惖淖饔糜虻?#xff0c;所以此時(shí)派生類的該成員會(huì)隱藏基類同名成員:
,我們也可以使用作用域操作符來(lái)顯式地調(diào)用基類中隱藏的成員:
- 在繼承場(chǎng)景下,函數(shù)調(diào)用的解析過(guò)程,注意在類型檢查前做命名查詢:
- 在繼承的場(chǎng)景下, 為了能夠讓基類的指針釋放動(dòng)態(tài)綁定的派生類對(duì)象,通過(guò)將基類的析構(gòu)函數(shù)聲明為
virtual
:,否則就會(huì)發(fā)生
undefined behavior
: - 如果一個(gè)類顯式定義了一個(gè)析構(gòu)函數(shù),那么編譯器不會(huì)默認(rèn)合成
move operation
: - 派生類的析構(gòu)函數(shù)會(huì)自動(dòng)調(diào)用基類的析構(gòu):
- 在繼承場(chǎng)景下,析構(gòu)函數(shù)的執(zhí)行順序與構(gòu)造函數(shù)相反:
,因?yàn)樵趫?zhí)行基類的構(gòu)造/析構(gòu)時(shí),如果是派生類的對(duì)象,那么該對(duì)象此時(shí)就是不完整的。為了安全考慮,在構(gòu)造/析構(gòu)執(zhí)行虛函數(shù)時(shí)就不談動(dòng)態(tài)綁定一說(shuō):
- 容器存儲(chǔ)繼承層次中的對(duì)象時(shí)應(yīng)該間接進(jìn)行:
,例如使用指向基類的指針等。