當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > C語(yǔ)言與CPP編程
[導(dǎo)讀]多態(tài)什么是多態(tài),有什么用C多態(tài)有兩種:靜態(tài)多態(tài)(早綁定)、動(dòng)態(tài)多態(tài)(晚綁定)。靜態(tài)多態(tài)是通過(guò)函數(shù)重載實(shí)現(xiàn)的;動(dòng)態(tài)多態(tài)是通過(guò)虛函數(shù)實(shí)現(xiàn)的。定義:“一個(gè)接口,多種方法”,程序在運(yùn)行時(shí)才決定要調(diào)用的函數(shù)。實(shí)現(xiàn):C多態(tài)性主要是通過(guò)虛函數(shù)實(shí)現(xiàn)的,虛函數(shù)允許子類(lèi)重寫(xiě)override(注意和o...

多態(tài)

什么是多態(tài),有什么用

C 多態(tài)有兩種:靜態(tài)多態(tài)(早綁定)、動(dòng)態(tài)多態(tài)(晚綁定)。靜態(tài)多態(tài)是通過(guò)函數(shù)重載實(shí)現(xiàn)的;動(dòng)態(tài)多態(tài)是通過(guò)虛函數(shù)實(shí)現(xiàn)的。

  • 定義:“一個(gè)接口,多種方法”,程序在運(yùn)行時(shí)才決定要調(diào)用的函數(shù)。
  • 實(shí)現(xiàn):C 多態(tài)性主要是通過(guò)虛函數(shù)實(shí)現(xiàn)的,虛函數(shù)允許子類(lèi)重寫(xiě) override(注意和 overload 的區(qū)別,overload 是重載,是允許同名函數(shù)的表現(xiàn),這些函數(shù)參數(shù)列表/類(lèi)型不同)。
注:多態(tài)與非多態(tài)的實(shí)質(zhì)區(qū)別就是函數(shù)地址是靜態(tài)綁定還是動(dòng)態(tài)綁定。如果函數(shù)的調(diào)用在編譯器編譯期間就可以確定函數(shù)的調(diào)用地址,并產(chǎn)生代碼,說(shuō)明地址是靜態(tài)綁定的;如果函數(shù)調(diào)用的地址是需要在運(yùn)行期間才確定,屬于動(dòng)態(tài)綁定。

  • 目的:接口重用。封裝可以使得代碼模塊化,繼承可以擴(kuò)展已存在的代碼,他們的目的都是為了代碼重用。而多態(tài)的目的則是為了接口重用。
  • 用法:聲明基類(lèi)的指針,利用該指針指向任意一個(gè)子類(lèi)對(duì)象,調(diào)用相應(yīng)的虛函數(shù),可以根據(jù)指向的子類(lèi)的不同而實(shí)現(xiàn)不同的方法。
用一句話概括:在基類(lèi)的函數(shù)前加上 virtual 關(guān)鍵字,在派生類(lèi)中重寫(xiě)該函數(shù),運(yùn)行時(shí)將會(huì)根據(jù)對(duì)象的實(shí)際類(lèi)型來(lái)調(diào)用相應(yīng)的函數(shù)。如果對(duì)象類(lèi)型是派生類(lèi),就調(diào)用派生類(lèi)的函數(shù);如果對(duì)象類(lèi)型是基類(lèi),就調(diào)用基類(lèi)的函數(shù)。

重寫(xiě)、重載與隱藏的區(qū)別

Overload 重載

在 C 程序中,可以將語(yǔ)義、功能相似的幾個(gè)函數(shù)用同一個(gè)名字表示,但參數(shù)或返回值不同(包括類(lèi)型、順序不同),即函數(shù)重載。

  • 相同的范圍(在同一個(gè)類(lèi)中);
  • 函數(shù)名字相同;
  • 參數(shù)不同;
  • virtual 關(guān)鍵字可有可無(wú);

Override(覆蓋或重寫(xiě))

是指派生類(lèi)函數(shù)覆蓋基類(lèi)函數(shù),特征是:

  • 不同的范圍(分別位于派生類(lèi)與基類(lèi));
  • 函數(shù)名字相同;參數(shù)相同;
  • 基類(lèi)函數(shù)必須有 virtual 關(guān)鍵字。
注:重寫(xiě)基類(lèi)虛函數(shù)的時(shí)候,會(huì)自動(dòng)轉(zhuǎn)換這個(gè)函數(shù)為 virtual 函數(shù),不管有沒(méi)有加 virtual,因此重寫(xiě)的時(shí)候不加 virtual 也是可以的,不過(guò)為了易讀性,還是加上比較好。

Overwrite(重寫(xiě))隱藏,

是指派生類(lèi)的函數(shù)屏蔽了與其同名的基類(lèi)函數(shù),規(guī)則如下:

  • 如果派生類(lèi)的函數(shù)與基類(lèi)的函數(shù)同名,但是參數(shù)不同。此時(shí),不論有無(wú) virtual 關(guān)鍵字,基類(lèi)的函數(shù)將被隱藏(注意別與重載混淆)。
  • 如果派生類(lèi)的函數(shù)與基類(lèi)的函數(shù)同名,并且參數(shù)也相同,但是基類(lèi)函數(shù)沒(méi)有 virtual 關(guān)鍵字。此時(shí),基類(lèi)的函數(shù)被隱藏(注意別與覆蓋混淆)。

虛函數(shù)和純虛函數(shù)

  • 虛函數(shù):為了實(shí)現(xiàn)動(dòng)態(tài)綁定。使用基類(lèi)的引用或指針調(diào)用虛函數(shù)的時(shí)候會(huì)發(fā)生動(dòng)態(tài)綁定。
  • 純虛函數(shù):抽象類(lèi)
  • 構(gòu)造函數(shù)可以重載,但不能是虛函數(shù),析構(gòu)函數(shù)可以是虛函數(shù)。

基類(lèi)為什么需要虛析構(gòu)函數(shù)?

防止內(nèi)存泄漏。想去借助父類(lèi)指針去銷(xiāo)毀子類(lèi)對(duì)象的時(shí)候,不能去銷(xiāo)毀子類(lèi)對(duì)象。假如沒(méi)有虛析構(gòu)函數(shù),釋放一個(gè)由基類(lèi)指針指向的派生類(lèi)對(duì)象時(shí),不會(huì)觸發(fā)動(dòng)態(tài)綁定,則只會(huì)調(diào)用基類(lèi)的析構(gòu)函數(shù),不會(huì)調(diào)用派生類(lèi)的。派生類(lèi)中申請(qǐng)的空間則得不到釋放導(dǎo)致內(nèi)存泄漏。

構(gòu)造/析構(gòu)函數(shù)調(diào)用虛函數(shù)

派生類(lèi)對(duì)象構(gòu)造期間進(jìn)入基類(lèi)的構(gòu)造函數(shù)時(shí),對(duì)象類(lèi)型變成了基類(lèi)類(lèi)型,而不是派生類(lèi)類(lèi)型。

同樣,進(jìn)入基類(lèi)析構(gòu)函數(shù)時(shí),對(duì)象也是基類(lèi)類(lèi)型。

所以,虛函數(shù)始終僅僅調(diào)用基類(lèi)的虛函數(shù)(如果是基類(lèi)調(diào)用虛函數(shù)),不能達(dá)到多態(tài)的效果。

虛函數(shù)表

  • 產(chǎn)生時(shí)間:編譯期
  • 存儲(chǔ)位置:只讀數(shù)據(jù)段 .rodata
  • 虛指針:類(lèi)的每一個(gè)對(duì)象都包含一個(gè)虛指針(指向虛表),存在對(duì)象實(shí)例的最前面四個(gè)字節(jié)
  • 虛指針創(chuàng)建時(shí)間:構(gòu)造函數(shù)
注:虛表中的指針會(huì)指向其繼承的最近的一個(gè)類(lèi)的虛函數(shù)

const 相關(guān)

如何初始化 const 和 static 數(shù)據(jù)成員?

通常在類(lèi)外申明 static 成員,但是 static const 的整型( bool,char,int,long )可以在類(lèi)中聲明且初始化,static const 的其他類(lèi)型必須在類(lèi)外初始化(包括整型數(shù)組)。

static 和 const 分別怎么用,類(lèi)里面 static 和 const 可以同時(shí)修飾成員函數(shù)嗎?

static 的作用:對(duì) static 的三條作用做一句話總結(jié)。首先 static 的最主要功能是隱藏,其次因?yàn)?static 變量存放在靜態(tài)存儲(chǔ)區(qū),所以它具備持久性和默認(rèn)值 0。

對(duì)變量

局部變量

在局部變量之前加上關(guān)鍵字 static,局部變量就被定義成為一個(gè)局部靜態(tài)變量。

  • 內(nèi)存中的位置:靜態(tài)存儲(chǔ)區(qū)
  • 初始化:未經(jīng)初始化的全局靜態(tài)變量會(huì)被程序自動(dòng)初始化為0(自動(dòng)對(duì)象的值是任意的,除非他被顯示初始化)
  • 作用域:作用域仍為局部作用域,當(dāng)定義它的函數(shù)或者語(yǔ)句塊結(jié)束的時(shí)候,作用域隨之結(jié)束。
注:當(dāng) static 用來(lái)修飾局部變量的時(shí)候,它就改變了局部變量的存儲(chǔ)位置(從原來(lái)的棧中存放改為靜態(tài)存儲(chǔ)區(qū))及其生命周期(局部靜態(tài)變量在離開(kāi)作用域之后,并沒(méi)有被銷(xiāo)毀,而是仍然駐留在內(nèi)存當(dāng)中,直到程序結(jié)束,只不過(guò)我們不能再對(duì)他進(jìn)行訪問(wèn)),但未改變其作用域。

全局變量

在全局變量之前加上關(guān)鍵字 static,全局變量就被定義成為一個(gè)全局靜態(tài)變量。

  • 內(nèi)存中的位置:靜態(tài)存儲(chǔ)區(qū)(靜態(tài)存儲(chǔ)區(qū)在整個(gè)程序運(yùn)行期間都存在)
  • 初始化:未經(jīng)初始化的全局靜態(tài)變量會(huì)被程序自動(dòng)初始化為 0(自動(dòng)對(duì)象的值是任意的,除非他被顯示初始化)
  • 作用域:全局靜態(tài)變量在聲明他的文件之外是不可見(jiàn)的。準(zhǔn)確地講從定義之處開(kāi)始到文件結(jié)尾。
注:static 修飾全局變量,并未改變其存儲(chǔ)位置及生命周期,而是改變了其作用域,使當(dāng)前文件外的源文件無(wú)法訪問(wèn)該變量,好處如下:

  • 不會(huì)被其他文件所訪問(wèn),修改
  • 其他文件中可以使用相同名字的變量,不會(huì)發(fā)生沖突。對(duì)全局函數(shù)也是有隱藏作用。而普通全局變量只要定義了,任何地方都能使用,使用前需要聲明所有的 .c 文件,只能定義一次普通全局變量,但是可以聲明多次(外部鏈接)。
注意:全局變量的作用域是全局范圍,但是在某個(gè)文件中使用時(shí),必須先聲明。

對(duì)類(lèi)

成員變量

用 static 修飾類(lèi)的數(shù)據(jù)成員實(shí)際使其成為類(lèi)的全局變量,會(huì)被類(lèi)的所有對(duì)象共享,包括派生類(lèi)的對(duì)象。因此,static 成員必須在類(lèi)外進(jìn)行初始化(初始化格式:int base::var=10;),而不能在構(gòu)造函數(shù)內(nèi)進(jìn)行初始化,不過(guò)也可以用 const 修飾 static 數(shù)據(jù)成員在類(lèi)內(nèi)初始化 。因?yàn)殪o態(tài)成員屬于整個(gè)類(lèi),而不屬于某個(gè)對(duì)象,如果在類(lèi)內(nèi)初始化,會(huì)導(dǎo)致每個(gè)對(duì)象都包含該靜態(tài)成員,這是矛盾的。

特點(diǎn):

  • 不要試圖在頭文件中定義(初始化)靜態(tài)數(shù)據(jù)成員。在大多數(shù)的情況下,這樣做會(huì)引起重復(fù)定義這樣的錯(cuò)誤。即使加上#ifndef #define #endif或者#pragma once也不行。
  • 靜態(tài)數(shù)據(jù)成員可以成為成員函數(shù)的可選參數(shù),而普通數(shù)據(jù)成員則不可以。
  • 靜態(tài)數(shù)據(jù)成員的類(lèi)型可以是所屬類(lèi)的類(lèi)型,而普通數(shù)據(jù)成員則不可以。普通數(shù)據(jù)成員的只能聲明為 所屬類(lèi)類(lèi)型的指針或引用。

成員函數(shù)

  • 用 static 修飾成員函數(shù),使這個(gè)類(lèi)只存在這一份函數(shù),所有對(duì)象共享該函數(shù),不含 this 指針。
  • 靜態(tài)成員是可以獨(dú)立訪問(wèn)的,也就是說(shuō),無(wú)須創(chuàng)建任何對(duì)象實(shí)例就可以訪問(wèn)。base::func(5,3);當(dāng) static 成員函數(shù)在類(lèi)外定義時(shí)不需要加 static 修飾符。
  • 在靜態(tài)成員函數(shù)的實(shí)現(xiàn)中不能直接引用類(lèi)中說(shuō)明的非靜態(tài)成員,可以引用類(lèi)中說(shuō)明的靜態(tài)成員。因?yàn)殪o態(tài)成員函數(shù)不含this指針。
不可以同時(shí)用 const 和 static 修飾成員函數(shù)。

C 編譯器在實(shí)現(xiàn) const 的成員函數(shù)的時(shí)候?yàn)榱舜_保該函數(shù)不能修改類(lèi)的實(shí)例的狀態(tài),會(huì)在函數(shù)中添加一個(gè)隱式的參數(shù) const this*。但當(dāng)一個(gè)成員為 static 的時(shí)候,該函數(shù)是沒(méi)有 this 指針的。也就是說(shuō)此時(shí) const 的用法和 static 是沖突的。

我們也可以這樣理解:兩者的語(yǔ)意是矛盾的。static 的作用是表示該函數(shù)只作用在類(lèi)型的靜態(tài)變量上,與類(lèi)的實(shí)例沒(méi)有關(guān)系;而 const 的作用是確保函數(shù)不能修改類(lèi)的實(shí)例的狀態(tài),與類(lèi)型的靜態(tài)變量沒(méi)有關(guān)系。因此不能同時(shí)用它們。

const的作用:

  • 限定變量為不可修改。
  • 限定成員函數(shù)不可以修改任何數(shù)據(jù)成員。
  • const 與指針:
const char *p 常量指針,可以換方向,不可以改內(nèi)容

char * const p,指針常量,不可以換方向,可以改內(nèi)容

構(gòu)造函數(shù)

構(gòu)造函數(shù)調(diào)用順序

  • 虛基類(lèi)構(gòu)造函數(shù)(被繼承的順序)
  • 非虛基類(lèi)構(gòu)造函數(shù)(被繼承的順序)
  • 成員對(duì)象構(gòu)造函數(shù)(聲明順序)
  • 自己的構(gòu)造函數(shù)

自身構(gòu)造函數(shù)順序

  • 虛表指針(防止初始化列表里面調(diào)用虛函數(shù),否則調(diào)用的是父類(lèi)的虛函數(shù))
  • 初始化列表(const、引用、沒(méi)有定義默認(rèn)構(gòu)造函數(shù)的類(lèi)型)
  • 花括號(hào)里的 (初始化列表直接初始化,這個(gè)先初始化后賦值)

this 指針

創(chuàng)建時(shí)間:成員函數(shù)調(diào)用前生成,調(diào)用后清除

如何傳遞給成員函數(shù):通過(guò)函數(shù)參數(shù)的首參數(shù)來(lái)傳遞

extern 關(guān)鍵字

  • 置于變量或者函數(shù)前,以標(biāo)示變量或者函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時(shí)在其他模塊中尋找其定義
  • extern “C” void fun(); 告訴編譯器按C的規(guī)則去翻譯

以下關(guān)鍵字的作用?使用場(chǎng)景?

  • inline:在 c/c 中,為了解決一些頻繁調(diào)用的小函數(shù)大量消耗??臻g(棧內(nèi)存)的問(wèn)題,特別的引入了 inline 修飾符,表示為內(nèi)聯(lián)函數(shù)。
  • decltype:從表達(dá)式中推斷出要定義變量的類(lèi)型,但卻不想用表達(dá)式的值去初始化變量。還有可能是函數(shù)的返回類(lèi)型為某表達(dá)式的的值類(lèi)型。
  • volatile:volatile 關(guān)鍵字是一種類(lèi)型修飾符,用它聲明的類(lèi)型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng)、硬件或者其它線程等。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對(duì)訪問(wèn)該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對(duì)特殊地址的穩(wěn)定訪問(wèn)。

淺拷貝與深拷貝

什么時(shí)候用到拷貝函數(shù)?

  • 一個(gè)對(duì)象以值傳遞的方式傳入函數(shù)體(參數(shù));
  • 一個(gè)對(duì)象以值傳遞的方式從函數(shù)返回(返回值);
  • 一個(gè)對(duì)象需要通過(guò)另外一個(gè)對(duì)象進(jìn)行初始化(初始化)。
如果在類(lèi)中沒(méi)有顯式地聲明一個(gè)拷貝構(gòu)造函數(shù),那么,編譯器將會(huì)自動(dòng)生成一個(gè)默認(rèn)的拷貝構(gòu)造函數(shù),該構(gòu)造函數(shù)完成對(duì)象之間的位拷貝。位拷貝又稱淺拷貝

默認(rèn)拷貝構(gòu)造函數(shù)是淺拷貝。如果一個(gè)類(lèi)擁有資源,當(dāng)這個(gè)類(lèi)的對(duì)象發(fā)生復(fù)制過(guò)程的時(shí)候,資源重新分配,這個(gè)過(guò)程就是深拷貝,反之,沒(méi)有重新分配資源,就是淺拷貝。

如果實(shí)行位拷貝,也就是把對(duì)象里的值完全復(fù)制給另一個(gè)對(duì)象,如 A=B。這時(shí),如果 B 中有一個(gè)成員變量指針已經(jīng)申請(qǐng)了內(nèi)存,那 A 中的那個(gè)成員變量也指向同一塊內(nèi)存。這就出現(xiàn)了問(wèn)題:當(dāng) B 把內(nèi)存釋放了(如:析構(gòu)),這時(shí)A內(nèi)的指針就是野指針了,出現(xiàn)運(yùn)行錯(cuò)誤。

C 類(lèi)中成員初始化順序

成員變量在使用初始化列表初始化時(shí),與構(gòu)造函數(shù)中初始化成員列表的順序無(wú)關(guān),只與定義成員變量的順序有關(guān)。

類(lèi)中 const 成員常量必須在構(gòu)造函數(shù)初始化列表中初始化。類(lèi)中 static 成員變量,只能在類(lèi)外初始化(同一類(lèi)的所有實(shí)例共享靜態(tài)成員變量)。

構(gòu)造過(guò)程

  • 分配內(nèi)存
  • 進(jìn)行父類(lèi)的構(gòu)造,按照父類(lèi)的聲明順序(遞歸過(guò)程)
  • 構(gòu)造虛表指針,對(duì)虛表指針賦值
  • 根據(jù)初始化列表中的值初始化變量
  • 執(zhí)行構(gòu)造函數(shù){}內(nèi)的

構(gòu)造函數(shù)初始化列表

const 或引用類(lèi)型的成員。因?yàn)?const 對(duì)象或引用類(lèi)型只能初始化,不能對(duì)他們賦值。

與對(duì)數(shù)據(jù)成員賦值的區(qū)別:

  • 內(nèi)置數(shù)據(jù)類(lèi)型,復(fù)合類(lèi)型(指針,引用):結(jié)果和性能上相同。
  • 用戶定義類(lèi)型(類(lèi)類(lèi)型):結(jié)果上相同,但是性能上存在很大的差別。

vector 中 size() 和 capacity() 的區(qū)別

size() 指容器當(dāng)前擁有的元素個(gè)數(shù)(對(duì)應(yīng)的resize(size_type)會(huì)在容器尾添加或刪除一些元素,來(lái)調(diào)整容器中實(shí)際的內(nèi)容,使容器達(dá)到指定的大小。);capacity()指容器在必須分配存儲(chǔ)空間之前可以存儲(chǔ)的元素總數(shù)。

size 表示的這個(gè) vector 里容納了多少個(gè)元素,capacity 表示 vector 能夠容納多少元素,它們的不同是在于 vector 的 size 是 2 倍增長(zhǎng)的。如果 vector 的大小不夠了,比如現(xiàn)在的 capacity 是 4,插入到第五個(gè)元素的時(shí)候,發(fā)現(xiàn)不夠了,此時(shí)會(huì)給他重新分配 8 個(gè)空間,把原來(lái)的數(shù)據(jù)及新的數(shù)據(jù)復(fù)制到這個(gè)新分配的空間里。(會(huì)有迭代器失效的問(wèn)題)

定義一個(gè)空類(lèi)編譯器做了哪些操作

如果你只是聲明一個(gè)空類(lèi),不做任何事情的話,編譯器會(huì)自動(dòng)為你生成一個(gè)默認(rèn)構(gòu)造函數(shù)、一個(gè)拷貝默認(rèn)構(gòu)造函數(shù)、一個(gè)默認(rèn)拷貝賦值操作符和一個(gè)默認(rèn)析構(gòu)函數(shù)。這些函數(shù)只有在第一次被調(diào)用時(shí),才會(huì)被編譯器創(chuàng)建。所有這些函數(shù)都是 inline 和 public 的。

強(qiáng)制類(lèi)型轉(zhuǎn)換

static_cast

用法:static_cast < type-id > ( expression )

q1. 為什么需要 static_cast 強(qiáng)制轉(zhuǎn)換?

  • void指針->其他類(lèi)型指針 (不安全)
  • 改變通常的標(biāo)準(zhǔn)轉(zhuǎn)換
  • 用于類(lèi)層次結(jié)構(gòu)中基類(lèi)和子類(lèi)之間指針或引用的轉(zhuǎn)換。進(jìn)行上行轉(zhuǎn)換(把子類(lèi)的指針或引用轉(zhuǎn)換成基類(lèi)表示)是安全的;進(jìn)行下行轉(zhuǎn)換(把基類(lèi)指針或引用轉(zhuǎn)換成子類(lèi)指針或引用)時(shí),由于沒(méi)有動(dòng)態(tài)類(lèi)型檢查,所以是不安全的。
dynamic_cast

用法:dynamic_cast < type-id > ( expression )

dynamic_cast 主要用于類(lèi)層次間的上行轉(zhuǎn)換和下行轉(zhuǎn)換,還可以用于類(lèi)之間的交叉轉(zhuǎn)換(同一基類(lèi)的兩個(gè)同級(jí)派生類(lèi))。

在類(lèi)層次間進(jìn)行上行轉(zhuǎn)換時(shí),dynamic_caststatic_cast的效果是一樣的;在進(jìn)行下行轉(zhuǎn)換時(shí),dynamic_cast具有類(lèi)型檢查的功能,比static_cast更安全。

reinpreter_cast

它可以把一個(gè)指針轉(zhuǎn)換成一個(gè)整數(shù),也可以把一個(gè)整數(shù)轉(zhuǎn)換成一個(gè)指針(先把一個(gè)指針轉(zhuǎn)換成一個(gè)整數(shù),在把該整數(shù)轉(zhuǎn)換成原類(lèi)型的指針,還可以得到原先的指針值)。

const_cast該運(yùn)算符用來(lái)修改類(lèi)型的 const 或 volatile 屬性。除了 const ?或 volatile 修飾之外, type_id 和 expression 的類(lèi)型是一樣的。

常量指針被轉(zhuǎn)化成非常量指針,并且仍然指向原來(lái)的對(duì)象;常量引用被轉(zhuǎn)換成非常量引用,并且仍然指向原來(lái)的對(duì)象;常量對(duì)象被轉(zhuǎn)換成非常量對(duì)象。

volatile 關(guān)鍵字

  • 使用方法:int volatile x;
  • 作用:編譯器不再優(yōu)化。讓編譯器每次操作該變量時(shí)一定要從內(nèi)存中真正取出,而不是使用已經(jīng)存在寄存器中的值 。

內(nèi)存管理

C 內(nèi)存分配

  • malloc:在內(nèi)存的動(dòng)態(tài)分配區(qū)域中分配一個(gè)長(zhǎng)度為 size 的連續(xù)空間,如果分配成功,則返回所分配內(nèi)存空間的首地址,否則返回 NULL,申請(qǐng)的內(nèi)存不會(huì)初始化。
  • calloc:分配一個(gè) num * size 連續(xù)的空間,會(huì)自動(dòng)初始化為0。
  • realloc:動(dòng)態(tài)分配一個(gè)長(zhǎng)度為 size 的內(nèi)存空間,并把內(nèi)存空間的首地址賦值給 ptr,把 ptr 內(nèi)存空間調(diào)整為 size。

C 內(nèi)存分配:

-棧區(qū)(stack):主要存放函數(shù)參數(shù)以及局部變量,由系統(tǒng)自動(dòng)分配釋放。

  • 堆區(qū)(heap):由用戶通過(guò) malloc/new 手動(dòng)申請(qǐng),手動(dòng)釋放。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類(lèi)似于鏈表。
  • 全局/靜態(tài)區(qū):存放全局變量、靜態(tài)變量;程序結(jié)束后由系統(tǒng)釋放。- - 字符串常量區(qū):字符串常量就放在這里,程序結(jié)束后由系統(tǒng)釋放。
  • 代碼區(qū):存放程序的二進(jìn)制代碼。

結(jié)構(gòu)體字節(jié)對(duì)齊問(wèn)題?結(jié)構(gòu)體/類(lèi)大小的計(jì)算?

默認(rèn)字節(jié)對(duì)齊

各成員變量存放的起始地址相對(duì)于結(jié)構(gòu)的起始地址的偏移量必須是該變量的類(lèi)型所占用的字節(jié)數(shù)的倍數(shù),結(jié)構(gòu)的大小為結(jié)構(gòu)的字節(jié)邊界數(shù)(即該結(jié)構(gòu)中占用最大空間的類(lèi)型所占用的字節(jié)數(shù))的倍數(shù) n 字節(jié)對(duì)齊。

pragma pack(n)

  • 如果 n 大于等于該變量所占用的字節(jié)數(shù),那么偏移量必須滿足默認(rèn)的對(duì)齊方式;
  • 如果 n 小于該變量的類(lèi)型所占用的字節(jié)數(shù),那么偏移量為 n 的倍數(shù),不用滿足默認(rèn)的對(duì)齊方式;
  • 如果 n 大于所有成員變量類(lèi)型所占用的字節(jié)數(shù),那么結(jié)構(gòu)體的總大小必須為占用空間最大的變量占用的空間數(shù)的倍數(shù);否則必須為n的倍數(shù)(兩者相比,取小);

虛函數(shù)的大小計(jì)算

假設(shè)經(jīng)過(guò)成員對(duì)齊后的類(lèi)的大小為 size 個(gè)字節(jié)。那么類(lèi)的 sizeof 大小可以這么計(jì)算:size 4*(虛函數(shù)指針的個(gè)數(shù) n)。

聯(lián)合體的大小計(jì)算

聯(lián)合體所占的空間不僅取決于最寬成員,還跟所有成員有關(guān)系,即其大小必須滿足兩個(gè)條件:

  • 大小足夠容納最寬的成員;
  • 大小能被其包含的所有基本數(shù)據(jù)類(lèi)型的大小所整除。
常見(jiàn)例子:

class?A?{};:?sizeof(A)?=?1;
class?A?{?virtual?Fun(){}?};:?sizeof(A)?=?4(32位機(jī)器)/8(64位機(jī)器);
class?A?{?static?int?a;?};:?sizeof(A)?=?1;
class?A?{?int?a;?};:?sizeof(A)?=?4;
class?A?{?static?int?a;?int?b;?};:?sizeof(A)?=?4;

指針和引用

區(qū)別

  • 定義:指針是一個(gè)對(duì)象,引用本身不是對(duì)象,只是另一個(gè)對(duì)象的別名;
  • 指針是“指向”另外一種類(lèi)型的復(fù)合類(lèi)型;
  • 引用本身不是一個(gè)對(duì)象,所以不能定義引用的引用;
  • 引用只能綁定到對(duì)象上,它只是一個(gè)對(duì)象的別名,因此引用必須初始化,且不能更換引用對(duì)象。

指針

可以有 const 指針,但是沒(méi)有 const 引用(const 引用可讀不可改,與綁定對(duì)象是否為 const 無(wú)關(guān))

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