當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > C語(yǔ)言與CPP編程
[導(dǎo)讀]一、關(guān)于對(duì)象C語(yǔ)言是程序性的,語(yǔ)言本身并沒(méi)有支持?jǐn)?shù)據(jù)和函數(shù)之間的關(guān)聯(lián)性C中可能采取抽象數(shù)據(jù)類型,或者是多層次的類結(jié)構(gòu)完成C的封裝并沒(méi)有增加多少成本,每一個(gè)成員函數(shù)雖然在class中聲明,但是卻不出現(xiàn)在每個(gè)對(duì)象中每一個(gè)非內(nèi)聯(lián)的成員函數(shù)只會(huì)誕生一個(gè)函數(shù)實(shí)例每個(gè)內(nèi)聯(lián)函數(shù)會(huì)在其每一個(gè)使用...


一、關(guān)于對(duì)象

  • C 語(yǔ)言是程序性的,語(yǔ)言本身并沒(méi)有支持?jǐn)?shù)據(jù)和函數(shù)之間的關(guān)聯(lián)性


  • C 中可能采取抽象數(shù)據(jù)類型,或者是多層次的類結(jié)構(gòu)完成


  • C 的封裝并沒(méi)有增加多少成本,每一個(gè)成員函數(shù)雖然在class中聲明,但是卻不出現(xiàn)在每個(gè)對(duì)象中


    • 每一個(gè)非內(nèi)聯(lián)的成員函數(shù)只會(huì)誕生一個(gè)函數(shù)實(shí)例
    • 每個(gè)內(nèi)聯(lián)函數(shù)會(huì)在其每一個(gè)使用者身上產(chǎn)生一個(gè)函數(shù)實(shí)例
  • C 在布局以及存儲(chǔ)時(shí)間上主要的額外負(fù)擔(dān)是由virtual引起的


    • 虛函數(shù)機(jī)制用以支持一個(gè)有效率的“執(zhí)行期綁定”
    • 虛基類用來(lái)實(shí)現(xiàn)“多次出現(xiàn)在繼承關(guān)系中的基類,有一個(gè)單一而被共享的實(shí)例”
  • 還有一些多重繼承下的額外負(fù)擔(dān),發(fā)生在一個(gè)派生類和其第二或后繼之基類的轉(zhuǎn)換之間


1.1 C 對(duì)象模式

  • C 對(duì)象模型有以下幾點(diǎn)
    • 每個(gè)類中存放一個(gè)指針?lè)Q為vptr,指向虛函數(shù)表
    • 表中每個(gè)都指向一個(gè)虛函數(shù)
    • 非靜態(tài)數(shù)據(jù)成員放在類對(duì)象內(nèi)
    • 靜態(tài)數(shù)據(jù)成員放在類對(duì)象外
    • 靜態(tài)和非靜態(tài)成員函數(shù)也放在類對(duì)象外
    • 虛函數(shù)則不同
C 對(duì)象模型

1.2 關(guān)鍵詞所帶來(lái)的差異

  • int ( *pq ) ( ); //聲明


  • 當(dāng)語(yǔ)言無(wú)法區(qū)分那是一個(gè)聲明還是一個(gè)表達(dá)式時(shí),我們需要一個(gè)超越語(yǔ)言范圍的規(guī)則,而該規(guī)則會(huì)將上述式子判斷為一個(gè)“聲明“


  • struct和class可以相互替換,他們只是默認(rèn)的權(quán)限不一樣


  • 如果一個(gè)程序員需要擁有C聲明的那種struct布局,可以抽出來(lái)單獨(dú)成為struct聲明,并且和C 部分組合起來(lái)


1.3 對(duì)象的差異

  • C 支持三種程序范式:程序模型、抽象數(shù)據(jù)類型模型、面向?qū)ο竽P?


    • 面向對(duì)象模型在繼承體系中 ,有時(shí)候編譯期間無(wú)法確定指針或引用所指類型
  • C 支持的多態(tài)類型:


    1. 經(jīng)由一組隱式的轉(zhuǎn)化操作:如派生類指針轉(zhuǎn)化為指向父類的指針
    2. 經(jīng)由虛函數(shù)機(jī)制
    3. 經(jīng)由dynamic_cast 和 typeid運(yùn)算符
  • 一個(gè)class所占的大小包括:


    • 其非靜態(tài)成員所占的大小
    • 由于內(nèi)存對(duì)齊填補(bǔ)上的大小
    • 加上支持虛函數(shù)而產(chǎn)生的大小
  • 指針的類型,只能代表其讓編譯器如何解釋其所指向的地址內(nèi)容,和它本身類型無(wú)關(guān),所以轉(zhuǎn)換其實(shí)是一種編譯器指令,不改變所指向的地址,只影響怎么解釋它給出的地址


  • 當(dāng)一個(gè)基類對(duì)象被初始化為一個(gè)子類對(duì)象時(shí),派生類就會(huì)被切割用來(lái)塞入較小的基類內(nèi)存中,派生類不會(huì)留下任何東西,多態(tài)也不會(huì)再呈現(xiàn)。


二、構(gòu)造函數(shù)語(yǔ)意學(xué)

2.1 默認(rèn)構(gòu)造函數(shù)的構(gòu)造操作

  • 以下四種情況下,會(huì)合成有用的構(gòu)造函數(shù):


    • 類聲明(或繼承)一個(gè)虛函數(shù)
    • 類派生自一個(gè)繼承串鏈,其中有一個(gè)或更多的虛基類
    • 帶有默認(rèn)構(gòu)造函數(shù)的成員函數(shù)對(duì)象,不過(guò)這個(gè)合成操作只有在構(gòu)造函數(shù)真正需要被調(diào)用時(shí)才發(fā)生,但只是調(diào)用其成員的默認(rèn)構(gòu)造函數(shù),其他則不會(huì)初始化
    • 如果一個(gè)派生類的父類帶有默認(rèn)構(gòu)造函數(shù),那么子類如果沒(méi)有定義構(gòu)造函數(shù),則會(huì)合成默認(rèn)構(gòu)造函數(shù),如果有的話但是沒(méi)有調(diào)用父類的,則編譯器會(huì)插入一些代碼調(diào)用父類的默認(rèn)構(gòu)造函數(shù)
    • 帶有一個(gè)虛函數(shù)的類
    • 帶有一個(gè)虛基類的類
  • C 新手常見(jiàn)的兩個(gè)誤解:


    • 任何class如果沒(méi)有定義默認(rèn)構(gòu)造函數(shù),就會(huì)被合成出來(lái)一個(gè)
    • 編譯器合成出來(lái)的默認(rèn)構(gòu)造函數(shù)會(huì)顯式設(shè)定類中的每一個(gè)數(shù)據(jù)成員的額 默認(rèn)值

2.2 拷貝構(gòu)造函數(shù)的構(gòu)造操作

  • 有三種情況會(huì)調(diào)用拷貝構(gòu)造函數(shù):


    • 對(duì)一個(gè)對(duì)象做顯式的初始化操作
    • 當(dāng)對(duì)象被當(dāng)作參數(shù)交給某個(gè)函數(shù)
    • 當(dāng)函數(shù)傳回一個(gè)類對(duì)象時(shí)
  • 如果類沒(méi)有聲明一個(gè)拷貝函數(shù),就會(huì)有隱式的聲明和隱式的定義出現(xiàn),同默認(rèn)構(gòu)造函數(shù)一樣在使用時(shí)才合成出來(lái)


  • 什么情況下一個(gè)類不展現(xiàn)“淺拷貝語(yǔ)意”:


    • 編譯器會(huì)合成一個(gè)拷貝構(gòu)造函數(shù),安插一些代碼用來(lái)設(shè)定虛基類指針和偏移的初值,對(duì)每個(gè)成員執(zhí)行必要的深拷貝初始化操作,以及執(zhí)行其他的內(nèi)存相關(guān)工作
    • 編譯器會(huì)顯式的設(shè)定新類的虛函數(shù)表,而不是直接拷貝過(guò)來(lái)指向同一個(gè)
    • 這兩個(gè)編譯器都會(huì)合成拷貝構(gòu)造函數(shù)并且安插進(jìn)那個(gè)成員和基類的拷貝構(gòu)造函數(shù)
    • 當(dāng)類內(nèi)含有一個(gè)成員類而后者的類聲明中有一個(gè)拷貝構(gòu)造函數(shù)(例如內(nèi)含有string成員變量)
    • 當(dāng)類繼承自一個(gè)基類而基類中存在拷貝構(gòu)造函數(shù)
    • 當(dāng)類聲明了一個(gè)或多個(gè)虛函數(shù)
    • 當(dāng)類派生自一個(gè)繼承串鏈,其中有一個(gè)或多個(gè)虛基類

2.3 程序轉(zhuǎn)化語(yǔ)意學(xué)

  • 在將一個(gè)類作為另一個(gè)類的初值情況下,語(yǔ)言允許編譯器有大量的自由發(fā)揮的空間,用來(lái)提升效率,但是缺點(diǎn)是不能安全的規(guī)劃拷貝構(gòu)造函數(shù)的副作用,必須視其執(zhí)行而定


  • 拷貝構(gòu)造的應(yīng)用,編譯器會(huì)多多少的進(jìn)行部分轉(zhuǎn)換,尤其是當(dāng)一個(gè)函數(shù)以值傳遞的方式傳回一個(gè)對(duì)象,而該對(duì)象有一個(gè)合成的構(gòu)造函數(shù),此外編譯器也會(huì)對(duì)拷貝構(gòu)造的調(diào)用進(jìn)行調(diào)優(yōu),以額外的第一參數(shù)取代NRV(Named Return Value)


2.4 成員們的初始化隊(duì)伍

  • 四種情況下你需要使用成員初始化列表
    • 當(dāng)初始化一個(gè)引用成員變量
    • 當(dāng)初始化一個(gè)const 成員變量
    • 當(dāng)調(diào)用一個(gè)基類的構(gòu)造函數(shù),而它擁有一組參數(shù)
    • 當(dāng)調(diào)用一個(gè)類成員變量的構(gòu)造函數(shù),而它擁有一組參數(shù)
class Word{
String _name;
int _cnt;
public:
Word(){
_name = 0;
_cnt = 0;
}
/*使用成員列表初始化可以解決
Word() : _name(0),_cnt(0){

}
*/

}
上式不會(huì)報(bào)錯(cuò),但是會(huì)有效率問(wèn)題,因?yàn)檫@樣會(huì)先產(chǎn)生一個(gè)臨時(shí)的string對(duì)象,然后將它初始化,之后以一個(gè)賦值運(yùn)算符將臨時(shí)對(duì)象指定給_name,再摧毀臨時(shí)的對(duì)象


  • 成員初始化列表中的初始化順序是按照類中的成員變量聲明的順序,與成員初始化列表的排列順序無(wú)關(guān)

3、Data語(yǔ)意學(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是因?yàn)榫幾g器的處理,在其中插入了1個(gè)char,為了讓其對(duì)象能在內(nèi)存中有自己獨(dú)立的地址


  • Y,Z是因?yàn)樘摶惐淼闹羔?


  • A 中含有Y和Z所以是8


  • 每一個(gè)類對(duì)象大小的影響因素:


    • 非靜態(tài)成員變量的大小
    • virtual特性
    • 內(nèi)存對(duì)齊

3.1 數(shù)據(jù)成員的綁定

  • 如果類的內(nèi)部有typedef,請(qǐng)把它放在類的起始處,因?yàn)榉乐瓜瓤吹降氖侨值暮瓦@個(gè)typedef相同的沖突,編譯器會(huì)選擇全局的,因?yàn)橄瓤吹饺值?

3.2 數(shù)據(jù)成員的布局

  • 非靜態(tài)成員變量的在內(nèi)存中的順序和其聲明順序是一致的
  • 但是不一定是連續(xù)的,因?yàn)橹虚g可能有內(nèi)存對(duì)齊的填補(bǔ)物
  • virtual機(jī)制的指針?biāo)诺奈恢煤途幾g器有關(guān)

3.3 成員變量的存取

  • 靜態(tài)變量都被放在一個(gè)全局區(qū),與類的大小無(wú)關(guān),正如對(duì)其取地址得到的是與類無(wú)關(guān)的數(shù)據(jù)類型,如果兩個(gè)類有相同的靜態(tài)成員變量,編譯器會(huì)暗自為其名稱編碼,使兩個(gè)名稱都不同
  • 非靜態(tài)成員變量則是直接放在對(duì)象內(nèi),經(jīng)由對(duì)象的地址和在類中的偏移地址取得,但是在繼承體系下,情況就會(huì)不一樣,因?yàn)榫幾g器無(wú)法確定此時(shí)的指針指的具體是父類對(duì)象還是子類對(duì)象

3.4 繼承下的數(shù)據(jù)成員

  • 在下面給定的兩個(gè)類中依次討論不同情況:



原本的數(shù)據(jù)模型
  • 在單一繼承沒(méi)有虛函數(shù)的情況下布局圖



單一繼承且無(wú)虛函數(shù)
  • 這種情況下常見(jiàn)錯(cuò)誤:
    • 可能會(huì)重復(fù)設(shè)計(jì)一些操作相同的函數(shù),我們可以把某些函數(shù)寫成inline,這樣就可以在子類中調(diào)用父類的某些函數(shù)來(lái)實(shí)現(xiàn)簡(jiǎn)化
    • 把數(shù)據(jù)放在同一個(gè)類中和繼承起來(lái)的內(nèi)存布局可能不同,因?yàn)槊總€(gè)類需要內(nèi)存對(duì)齊


    • 疊在一起的內(nèi)存布局


分層繼承的布局
可見(jiàn)內(nèi)存大了100%


  • 容易出現(xiàn)的不易發(fā)現(xiàn)的問(wèn)題:


繼承下易犯錯(cuò)誤
  • 當(dāng)加上多態(tài)之后,對(duì)空間上增加的額外負(fù)擔(dān)包括:

    • 析構(gòu)函數(shù)的調(diào)用順序是反向的,從子類到父類
    • 導(dǎo)入一個(gè)虛函數(shù)表,表中的個(gè)數(shù)是聲明的虛函數(shù)的個(gè)數(shù)加上一個(gè)或兩個(gè)slots(用來(lái)支持運(yùn)行類型識(shí)別)


    • 在每個(gè)對(duì)象中加入vptr,提供執(zhí)行期的鏈接,使每一個(gè)類能找到相應(yīng)的虛函數(shù)表


    • 加強(qiáng)構(gòu)造函數(shù),使它能夠?yàn)関ptr設(shè)定初值,讓它指向?qū)?yīng)的虛函數(shù)表,這可能意味著在派生類和每一個(gè)基類的構(gòu)造函數(shù)中,重新設(shè)定vptr的值


    • 加強(qiáng)析構(gòu)函數(shù),使它能夠消抹“指向類的相關(guān)虛函數(shù)表”的vptr,vptr很可能以及在子類析構(gòu)函數(shù)中被設(shè)定為子類的虛表地址。


    • 以下是三種情況不同的繼承下會(huì)有不同的布局


    • Vptr放在尾端


    • vptr放在前端




含虛函數(shù)的數(shù)據(jù)分布
  • 多重繼承

  • **單一繼承特點(diǎn):**派生類和父類對(duì)象都是從相同的地址開始,區(qū)別只是派生類比較大能容納自己的非靜態(tài)成員變量


  • 多重繼承下會(huì)比較復(fù)雜




多重繼承關(guān)系
  • 一個(gè)派生對(duì)象,把它的地址指定給最左邊的基類,和單一繼承一樣,因?yàn)槠鹗嫉刂肥且粯拥?,但是后面的需要更改,因?yàn)樾枰由锨懊婊惖拇笮?,才能得到后面基類的地?


多重繼承數(shù)據(jù)分布
  • 虛繼承

  • STL標(biāo)準(zhǔn)庫(kù)中使用的虛繼承:


  • 虛繼承關(guān)系圖


  • 虛繼承關(guān)系:





    虛繼承例子


  • 虛繼數(shù)據(jù)在內(nèi)存中的分布


  • 虛繼承數(shù)據(jù)模型


  • 虛繼承數(shù)據(jù)模型2


3.5 對(duì)象成員的效率

  • 程序員如果關(guān)心程序效率,應(yīng)該實(shí)際測(cè)試,不要光憑推論、常識(shí)判斷或假設(shè)。
  • 優(yōu)化操作并不一定總是能夠有效運(yùn)行,我不止一次以優(yōu)化方式來(lái) 編譯一個(gè)已通過(guò)編譯的正常程序,卻以失敗收?qǐng)?

3.6 指向數(shù)據(jù)成員的指針

  • vptr通常放在起始處或尾端,與編譯器有關(guān),C 標(biāo)準(zhǔn)允許放在類中的任何位置


  • 取某個(gè)類成員變量的地址,通常取到得的是在類的首地址的偏移位置


    • 例如
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

電感是導(dǎo)線內(nèi)通過(guò)交流電流時(shí),在導(dǎo)線的內(nèi)部及其周圍產(chǎn)生交變磁通,導(dǎo)線的磁通量與生產(chǎn)此磁通的電流之比。電感器也叫電感線圈,是利用電磁感應(yīng)原理制成的,由導(dǎo)線在絕緣管上單層或多層繞制而成的,導(dǎo)線彼此互相絕緣,而絕緣管可以是空心的...

關(guān)鍵字: 電感 磁通量 電感器

根據(jù)交通運(yùn)輸部水運(yùn)科學(xué)研究院提出的智慧港口的概念,智慧港口是利用新一代信息技術(shù),將港口相關(guān)業(yè)務(wù)和管理創(chuàng)新深度融合,使港口更加集約、高效、便捷、安全、綠色,創(chuàng)新港口發(fā)展模式,實(shí)現(xiàn)港口科學(xué)可持續(xù)發(fā)展。

關(guān)鍵字: 智慧港口 信息技術(shù) 業(yè)務(wù)

近年來(lái),世界主要汽車大國(guó)紛紛加強(qiáng)新能源汽車戰(zhàn)略謀劃、強(qiáng)化政策支持、完善產(chǎn)業(yè)布局,新能源汽車已成為全球汽車產(chǎn)業(yè)轉(zhuǎn)型發(fā)展的主要方向和促進(jìn)世界經(jīng)濟(jì)持續(xù)增長(zhǎng)的重要引擎。2021年,全國(guó)新能源汽車實(shí)現(xiàn)產(chǎn)量354.5萬(wàn)輛,銷量352...

關(guān)鍵字: 新能源 汽車 引擎

2007-2021年,全球針狀焦行業(yè)專利申請(qǐng)人數(shù)量及專利申請(qǐng)量總體呈現(xiàn)增長(zhǎng)態(tài)勢(shì)。雖然2021年全球針狀焦行業(yè)專利申請(qǐng)人數(shù)量及專利申請(qǐng)量有所下降,但是這兩大指標(biāo)數(shù)量仍較多。整體來(lái)看,全球針狀焦技術(shù)處于成長(zhǎng)期。

關(guān)鍵字: 針狀焦行業(yè) 專利申請(qǐng)人 增長(zhǎng)態(tài)勢(shì)

按企業(yè)主營(yíng)業(yè)務(wù)類型分,我國(guó)智能家居行業(yè)競(jìng)爭(zhēng)派系可分為傳統(tǒng)家電企業(yè)、互聯(lián)網(wǎng)企業(yè)以及其他企業(yè)三派。傳統(tǒng)家電企業(yè)代表有海爾智家、美的集團(tuán)、格力電器等,具有供應(yīng)鏈和銷售渠道,制造能力和品牌優(yōu)勢(shì)突出;互聯(lián)網(wǎng)企業(yè)代表有小米集團(tuán)、百度...

關(guān)鍵字: 智能家居 互聯(lián)網(wǎng)企業(yè) 供應(yīng)鏈

軍工電子是集紅外技術(shù)、激光技術(shù)、半導(dǎo)體及嵌入式技術(shù)與虛擬仿真技術(shù)為一體的綜合性軍工技術(shù)體系,是國(guó)防信息化建設(shè)的基石。軍工電子行業(yè)包含在軍工行業(yè)內(nèi),專注于軍工行業(yè)電子產(chǎn)品布局。根據(jù)其軍工產(chǎn)品的不同可分為衛(wèi)星導(dǎo)航、通信指揮、...

關(guān)鍵字: 軍工電子 嵌入式技術(shù) 信息化建設(shè)

我國(guó)汽車零配件行業(yè)細(xì)分種類眾多,從汽車零配件主要產(chǎn)品來(lái)看,發(fā)動(dòng)機(jī)系統(tǒng)行業(yè)內(nèi)有濰柴動(dòng)力、華域汽車等主要從業(yè)企業(yè);在車身零部件領(lǐng)域內(nèi),福耀玻璃、中策橡膠具有一定的規(guī)模優(yōu)勢(shì);行駛系統(tǒng)領(lǐng)域內(nèi)有中策橡膠提供的輪胎以及華為等企業(yè)提供...

關(guān)鍵字: 汽車零配件 發(fā)動(dòng)機(jī) 行駛系統(tǒng)

茶飲料是指以茶葉或茶葉的水提取液、濃縮液、茶粉(包括速溶茶粉、研磨茶粉)或直接以茶的鮮葉為原料添加或不添加食品原輔料和(或)食品添加劑,經(jīng)加工制成的液體飲料。根據(jù)國(guó)家標(biāo)準(zhǔn)《茶飲料(GB/T 21733-2008)》的規(guī)定...

關(guān)鍵字: 茶飲料 茶葉的水 食品添加劑

全球液壓行業(yè)專利技術(shù)在21世紀(jì)初得到初步發(fā)展,這一時(shí)期液壓專利申請(qǐng)人數(shù)量和申請(qǐng)量處于較低水平。2011-2012年,液壓行業(yè)專利技術(shù)的發(fā)展總體處于成長(zhǎng)期,2012年以后中全球液壓行業(yè)專利技術(shù)申請(qǐng)量或申請(qǐng)人數(shù)量整體處于波動(dòng)...

關(guān)鍵字: 液壓行業(yè) 專利授權(quán) 技術(shù)類型

從上市企業(yè)的總市值情況來(lái)看,2022年7月28日,中芯國(guó)際、紫光國(guó)微和韋爾股份總市值遙遙領(lǐng)先,中芯國(guó)際總市值達(dá)到3238.21億元,紫光國(guó)微總市值達(dá)到1358.77億元,韋爾股份總市值達(dá)到1277.07億元;其次是兆易創(chuàng)...

關(guān)鍵字: 上市企業(yè) 集成電路 行業(yè)

C語(yǔ)言與CPP編程

252 篇文章

關(guān)注

發(fā)布文章

編輯精選

更多

論壇熱帖

關(guān)閉