int ( *pq ) ( ); //聲明
當(dāng)語言無法區(qū)分那是一個聲明還是一個表達(dá)式時,我們需要一個超越語言范圍的規(guī)則,而該規(guī)則會將上述式子判斷為一個“聲明“
struct和class可以相互替換,他們只是默認(rèn)的權(quán)限不一樣
如果一個程序員需要擁有C聲明的那種struct布局,可以抽出來單獨成為struct聲明,并且和C 部分組合起來
1.3 對象的差異
C 支持三種程序范式:程序模型、抽象數(shù)據(jù)類型模型、面向?qū)ο竽P?
面向對象模型在繼承體系中 ,有時候編譯期間無法確定指針或引用所指類型
C 支持的多態(tài)類型:
經(jīng)由一組隱式的轉(zhuǎn)化操作:如派生類指針轉(zhuǎn)化為指向父類的指針
經(jīng)由虛函數(shù)機制
經(jīng)由dynamic_cast 和 typeid運算符
一個class所占的大小包括:
其非靜態(tài)成員所占的大小
由于內(nèi)存對齊填補上的大小
加上支持虛函數(shù)而產(chǎn)生的大小
指針的類型,只能代表其讓編譯器如何解釋其所指向的地址內(nèi)容,和它本身類型無關(guān),所以轉(zhuǎn)換其實是一種編譯器指令,不改變所指向的地址,只影響怎么解釋它給出的地址
當(dāng)一個基類對象被初始化為一個子類對象時,派生類就會被切割用來塞入較小的基類內(nèi)存中,派生類不會留下任何東西,多態(tài)也不會再呈現(xiàn)。
二、構(gòu)造函數(shù)語意學(xué)
2.1 默認(rèn)構(gòu)造函數(shù)的構(gòu)造操作
以下四種情況下,會合成有用的構(gòu)造函數(shù):
類聲明(或繼承)一個虛函數(shù)
類派生自一個繼承串鏈,其中有一個或更多的虛基類
帶有默認(rèn)構(gòu)造函數(shù)的成員函數(shù)對象,不過這個合成操作只有在構(gòu)造函數(shù)真正需要被調(diào)用時才發(fā)生,但只是調(diào)用其成員的默認(rèn)構(gòu)造函數(shù),其他則不會初始化
如果一個派生類的父類帶有默認(rèn)構(gòu)造函數(shù),那么子類如果沒有定義構(gòu)造函數(shù),則會合成默認(rèn)構(gòu)造函數(shù),如果有的話但是沒有調(diào)用父類的,則編譯器會插入一些代碼調(diào)用父類的默認(rèn)構(gòu)造函數(shù)
帶有一個虛函數(shù)的類
帶有一個虛基類的類
C 新手常見的兩個誤解:
任何class如果沒有定義默認(rèn)構(gòu)造函數(shù),就會被合成出來一個
編譯器合成出來的默認(rèn)構(gòu)造函數(shù)會顯式設(shè)定類中的每一個數(shù)據(jù)成員的額 默認(rèn)值
2.2 拷貝構(gòu)造函數(shù)的構(gòu)造操作
有三種情況會調(diào)用拷貝構(gòu)造函數(shù):
對一個對象做顯式的初始化操作
當(dāng)對象被當(dāng)作參數(shù)交給某個函數(shù)
當(dāng)函數(shù)傳回一個類對象時
如果類沒有聲明一個拷貝函數(shù),就會有隱式的聲明和隱式的定義出現(xiàn),同默認(rèn)構(gòu)造函數(shù)一樣在使用時才合成出來
什么情況下一個類不展現(xiàn)“淺拷貝語意”:
編譯器會合成一個拷貝構(gòu)造函數(shù),安插一些代碼用來設(shè)定虛基類指針和偏移的初值,對每個成員執(zhí)行必要的深拷貝初始化操作,以及執(zhí)行其他的內(nèi)存相關(guān)工作
編譯器會顯式的設(shè)定新類的虛函數(shù)表,而不是直接拷貝過來指向同一個
這兩個編譯器都會合成拷貝構(gòu)造函數(shù)并且安插進那個成員和基類的拷貝構(gòu)造函數(shù)
當(dāng)類內(nèi)含有一個成員類而后者的類聲明中有一個拷貝構(gòu)造函數(shù)(例如內(nèi)含有string成員變量)
當(dāng)類繼承自一個基類而基類中存在拷貝構(gòu)造函數(shù)
當(dāng)類聲明了一個或多個虛函數(shù)
當(dāng)類派生自一個繼承串鏈,其中有一個或多個虛基類
2.3 程序轉(zhuǎn)化語意學(xué)
在將一個類作為另一個類的初值情況下,語言允許編譯器有大量的自由發(fā)揮的空間,用來提升效率,但是缺點是不能安全的規(guī)劃拷貝構(gòu)造函數(shù)的副作用,必須視其執(zhí)行而定
拷貝構(gòu)造的應(yīng)用,編譯器會多多少的進行部分轉(zhuǎn)換,尤其是當(dāng)一個函數(shù)以值傳遞的方式傳回一個對象,而該對象有一個合成的構(gòu)造函數(shù),此外編譯器也會對拷貝構(gòu)造的調(diào)用進行調(diào)優(yōu),以額外的第一參數(shù)取代NRV(Named Return Value)
2.4 成員們的初始化隊伍
四種情況下你需要使用成員初始化列表
當(dāng)初始化一個引用成員變量
當(dāng)初始化一個const 成員變量
當(dāng)調(diào)用一個基類的構(gòu)造函數(shù),而它擁有一組參數(shù)
當(dāng)調(diào)用一個類成員變量的構(gòu)造函數(shù),而它擁有一組參數(shù)
class Word{
String _name;
int _cnt;
public:
Word(){
_name = 0;
_cnt = 0;
}
/*使用成員列表初始化可以解決
Word() : _name(0),_cnt(0){
}
*/
}
上式不會報錯,但是會有效率問題,因為這樣會先產(chǎn)生一個臨時的string對象,然后將它初始化,之后以一個賦值運算符將臨時對象指定給_name,再摧毀臨時的對象
-
成員初始化列表中的初始化順序是按照類中的成員變量聲明的順序,與成員初始化列表的排列順序無關(guān)
3、Data語意學(xué)
class X{};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y,public Z {};
sizeof(X) //1
sizeof(Y) //4
sizeof(Z) //4
sizeof(A) //8
-
X為1是因為編譯器的處理,在其中插入了1個char,為了讓其對象能在內(nèi)存中有自己獨立的地址
-
Y,Z是因為虛基類表的指針
-
A 中含有Y和Z所以是8
-
每一個類對象大小的影響因素:
-
非靜態(tài)成員變量的大小
-
virtual特性
-
內(nèi)存對齊
3.1 數(shù)據(jù)成員的綁定
-
如果類的內(nèi)部有typedef,請把它放在類的起始處,因為防止先看到的是全局的和這個typedef相同的沖突,編譯器會選擇全局的,因為先看到全局的
3.2 數(shù)據(jù)成員的布局
-
非靜態(tài)成員變量的在內(nèi)存中的順序和其聲明順序是一致的
-
但是不一定是連續(xù)的,因為中間可能有內(nèi)存對齊的填補物
-
virtual機制的指針?biāo)诺奈恢煤途幾g器有關(guān)
3.3 成員變量的存取
-
靜態(tài)變量都被放在一個全局區(qū),與類的大小無關(guān),正如對其取地址得到的是與類無關(guān)的數(shù)據(jù)類型,如果兩個類有相同的靜態(tài)成員變量,編譯器會暗自為其名稱編碼,使兩個名稱都不同
-
非靜態(tài)成員變量則是直接放在對象內(nèi),經(jīng)由對象的地址和在類中的偏移地址取得,但是在繼承體系下,情況就會不一樣,因為編譯器無法確定此時的指針指的具體是父類對象還是子類對象
3.4 繼承下的數(shù)據(jù)成員
-
在下面給定的兩個類中依次討論不同情況:
原本的數(shù)據(jù)模型
-
在單一繼承沒有虛函數(shù)的情況下布局圖
單一繼承且無虛函數(shù)
-
這種情況下常見錯誤:
-
可能會重復(fù)設(shè)計一些操作相同的函數(shù),我們可以把某些函數(shù)寫成inline,這樣就可以在子類中調(diào)用父類的某些函數(shù)來實現(xiàn)簡化
-
把數(shù)據(jù)放在同一個類中和繼承起來的內(nèi)存布局可能不同,因為每個類需要內(nèi)存對齊
-
疊在一起的內(nèi)存布局
分層繼承的布局
可見內(nèi)存大了100%
-
容易出現(xiàn)的不易發(fā)現(xiàn)的問題:
繼承下易犯錯誤
-
當(dāng)加上多態(tài)之后,對空間上增加的額外負(fù)擔(dān)包括:
-
析構(gòu)函數(shù)的調(diào)用順序是反向的,從子類到父類
-
導(dǎo)入一個虛函數(shù)表,表中的個數(shù)是聲明的虛函數(shù)的個數(shù)加上一個或兩個slots(用來支持運行類型識別)
-
在每個對象中加入vptr,提供執(zhí)行期的鏈接,使每一個類能找到相應(yīng)的虛函數(shù)表
-
加強構(gòu)造函數(shù),使它能夠為vptr設(shè)定初值,讓它指向?qū)?yīng)的虛函數(shù)表,這可能意味著在派生類和每一個基類的構(gòu)造函數(shù)中,重新設(shè)定vptr的值
-
加強析構(gòu)函數(shù),使它能夠消抹“指向類的相關(guān)虛函數(shù)表”的vptr,vptr很可能以及在子類析構(gòu)函數(shù)中被設(shè)定為子類的虛表地址。
-
以下是三種情況不同的繼承下會有不同的布局
-
Vptr放在尾端
-
-
vptr放在前端
-
含虛函數(shù)的數(shù)據(jù)分布
-
多重繼承
-
**單一繼承特點:**派生類和父類對象都是從相同的地址開始,區(qū)別只是派生類比較大能容納自己的非靜態(tài)成員變量
-
多重繼承下會比較復(fù)雜
多重繼承關(guān)系
-
一個派生對象,把它的地址指定給最左邊的基類,和單一繼承一樣,因為起始地址是一樣的,但是后面的需要更改,因為需要加上前面基類的大小,才能得到后面基類的地址
多重繼承數(shù)據(jù)分布
-
虛繼承
-
STL標(biāo)準(zhǔn)庫中使用的虛繼承:
-
虛繼承關(guān)系圖
-
-
虛繼承關(guān)系:
虛繼承例子
-
虛繼數(shù)據(jù)在內(nèi)存中的分布
-
虛繼承數(shù)據(jù)模型
-
-
虛繼承數(shù)據(jù)模型2
-
3.5 對象成員的效率
-
程序員如果關(guān)心程序效率,應(yīng)該實際測試,不要光憑推論、常識判斷或假設(shè)。
-
優(yōu)化操作并不一定總是能夠有效運行,我不止一次以優(yōu)化方式來 編譯一個已通過編譯的正常程序,卻以失敗收場
3.6 指向數(shù)據(jù)成員的指針
-
vptr通常放在起始處或尾端,與編譯器有關(guān),C 標(biāo)準(zhǔn)允許放在類中的任何位置
-
取某個類成員變量的地址,通常取到得的是在類的首地址的偏移位置
-
例如
根據(jù)交通運輸部水運科學(xué)研究院提出的智慧港口的概念,智慧港口是利用新一代信息技術(shù),將港口相關(guān)業(yè)務(wù)和管理創(chuàng)新深度融合,使港口更加集約、高效、便捷、安全、綠色,創(chuàng)新港口發(fā)展模式,實現(xiàn)港口科學(xué)可持續(xù)發(fā)展。
關(guān)鍵字: 智慧港口 信息技術(shù) 業(yè)務(wù)按企業(yè)主營業(yè)務(wù)類型分,我國智能家居行業(yè)競爭派系可分為傳統(tǒng)家電企業(yè)、互聯(lián)網(wǎng)企業(yè)以及其他企業(yè)三派。傳統(tǒng)家電企業(yè)代表有海爾智家、美的集團、格力電器等,具有供應(yīng)鏈和銷售渠道,制造能力和品牌優(yōu)勢突出;互聯(lián)網(wǎng)企業(yè)代表有小米集團、百度...
關(guān)鍵字: 智能家居 互聯(lián)網(wǎng)企業(yè) 供應(yīng)鏈軍工電子是集紅外技術(shù)、激光技術(shù)、半導(dǎo)體及嵌入式技術(shù)與虛擬仿真技術(shù)為一體的綜合性軍工技術(shù)體系,是國防信息化建設(shè)的基石。軍工電子行業(yè)包含在軍工行業(yè)內(nèi),專注于軍工行業(yè)電子產(chǎn)品布局。根據(jù)其軍工產(chǎn)品的不同可分為衛(wèi)星導(dǎo)航、通信指揮、...
關(guān)鍵字: 軍工電子 嵌入式技術(shù) 信息化建設(shè)我國汽車零配件行業(yè)細(xì)分種類眾多,從汽車零配件主要產(chǎn)品來看,發(fā)動機系統(tǒng)行業(yè)內(nèi)有濰柴動力、華域汽車等主要從業(yè)企業(yè);在車身零部件領(lǐng)域內(nèi),福耀玻璃、中策橡膠具有一定的規(guī)模優(yōu)勢;行駛系統(tǒng)領(lǐng)域內(nèi)有中策橡膠提供的輪胎以及華為等企業(yè)提供...
關(guān)鍵字: 汽車零配件 發(fā)動機 行駛系統(tǒng)全球液壓行業(yè)專利技術(shù)在21世紀(jì)初得到初步發(fā)展,這一時期液壓專利申請人數(shù)量和申請量處于較低水平。2011-2012年,液壓行業(yè)專利技術(shù)的發(fā)展總體處于成長期,2012年以后中全球液壓行業(yè)專利技術(shù)申請量或申請人數(shù)量整體處于波動...
關(guān)鍵字: 液壓行業(yè) 專利授權(quán) 技術(shù)類型