C++2021面試題大匯總(收藏級)


一、前言

在進入你心儀的公司之前,都會有一到N輪的C++面試與筆試,做我們這個行業的都是這樣,所以除了口語表達能力之外,還有一點就是實力!這也是你的C++面試題所要體現的,沒有經驗的可能不懂試題,告訴你一個方法,那個時候我真的用了,就是把所有你見過的重點題型都背下來!方法很老套又不切合實際,但是很有用!
以下推薦一些常見的C++面試題,希望能幫到你,也預祝各位面試成功進入自己心儀的公司!

更多阿里、百度、華為、美團、騰訊、頭條C++面試題可以關注微信公眾號“C和C加加”回復“面試題”即可獲取相關C++面試題!

二、C/C++的比較相關面試題

1. C和C++的區別?

1). C++是C的超集;
2). C是一個結構化語言,它的重點在於算法和數據結構。C程序的設計首要考慮的是如何通過一個過程,對輸入(或環境條件)進行運算處理得到輸出(或實現過程(事務)控制),而對於C++,首要考慮的是如何構造一個對象模型,讓這個模型能夠契合與之對應的問題域,這樣就可以通過獲取對象的狀態信息得到輸出或實現過程(事務)控制。

2. int fun() 和 int fun(void)的區別?

這里考察的是c 中的默認類型機制。
在c中,int fun() 會解讀為返回值為int(即使前面沒有int,也是如此,但是在c++中如果沒有返回類型將報錯),輸入類型和個數沒有限制, 而int fun(void)則限制輸入類型為一個void。
在c++下,這兩種情況都會解讀為返回int類型,輸入void類型。

3.delete與 delete []區別

delete只會調用一次析構函數,而delete[]會調用每一個成員的析構函數。在More Effective C++中有更為詳細的解釋:“當delete操作符用於數組時,它為每個數組元素調用析構函數,然后調用operator delete來釋放內存。”delete與new配套,delete []與new []配套

MemTest *mTest1=new MemTest[10];

MemTest *mTest2=new MemTest;

Int *pInt1=new int [10];

Int *pInt2=new int;

delete[]pInt1; //-1-

delete[]pInt2; //-2-

delete[]mTest1;//-3-

delete[]mTest2;//-4-

在-4-處報錯。

這就說明:對於內建簡單數據類型,delete和delete[]功能是相同的。對於自定義的復雜數據類型,delete和delete[]不能互用。delete[]刪除一個數組,delete刪除一個指針。簡單來說,用new分配的內存用delete刪除;用new[]分配的內存用delete[]刪除。delete[]會調用數組元素的析構函數。內部數據類型沒有析構函數,所以問題不大。如果你在用delete時沒用括號,delete就會認為指向的是單個對象,否則,它就會認為指向的是一個數組。

4.new、delete、malloc、free關系

delete會調用對象的析構函數,和new對應free只會釋放內存,new調用構造函數。malloc與free是C++/C語言的標准庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free。因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。

5.const  與 #define 的比較 ,const有什么優點?

(1) const 常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。而對后者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤(邊際效應) 。

(2)  有些集成化的調試工具可以對 const 常量進行調試,但是不能對宏常量進行調試。

6. const 有什么用途

主要有幾點:
1).定義只讀變量,或者常量(只讀變量和常量的區別參考下面一條);
2).修飾函數的參數和函數的返回值;
3).修飾函數的定義體,這里的函數為類的成員函數,被const修飾的成員函數代表不能修改成員變量的值,因此const成員函數只能調用const成員函數;
4).只讀對象。只讀對象只能調用const成員函數。

class Screen {
public:
const char cha; //const成員變量
char get() const; //const成員函數
};

const Screen screen; //只讀對象

7. 在C中用const 能定義真正意義上的常量嗎?C++中的const呢?

不能。c中的const僅僅是從編譯層來限定,不允許對const 變量進行賦值操作,在運行期是無效的,所以並非是真正的常量(比如通過指針對const變量是可以修改值的),但是c++中是有區別的,c++在編譯時會把const常量加入符號表,以后(仍然在編譯期)遇到這個變量會從符號表中查找,所以在C++中是不可能修改到const變量的。
補充:
1)c中的局部const常量存儲在棧空間,全局const常量存在只讀存儲區,所以全局const常量也是無法修改的,它是一個只讀變量。
2)這里需要說明的是,常量並非僅僅是不可修改,而是相對於變量,它的值在編譯期已經決定,而不是在運行時決定。
3)c++中的const 和宏定義是有區別的,宏是在預編譯期直接進行文本替換,而const發生在編譯期,是可以進行類型檢查和作用域檢查的。
4)c語言中只有enum可以實現真正的常量。
5)c++中只有用字面量初始化的const常量會被加入符號表,而變量初始化的const常量依然只是只讀變量。
6)c++中const成員為只讀變量,可以通過指針修改const成員的值,另外const成員變量只能在初始化列表中進行初始化。

下面我們通過代碼來看看區別。
同樣一段代碼,在c編譯器下,打印結果為*pa = 4, 4
在c++編譯下打印的結果為 *pa = 4, 8

int main(void)
{
    const int a = 8;
    int *pa = (int *)&a;
    *pa = 4;
    printf("*pa = %d, a = %d", *pa, a);
    return 0;
}

另外值得一說的是,由於c++中const常量的值在編譯期就已經決定,下面的做法是OK的,但是c中是編譯通不過的。

int main(void)
{
    const int a = 8;
    const int b = 2;
    int array[a+b] = {0};
    return 0;
}

8. 宏和內聯(inline)函數的比較?

1)首先宏是C中引入的一種預處理功能;
2)內聯(inline)函數是C++中引用的一個新的關鍵字;C++中推薦使用內聯函數來替代宏代碼片段;
3)內聯函數將函數體直接擴展到調用內聯函數的地方,這樣減少了參數壓棧,跳轉,返回等過程;

4)由於內聯發生在編譯階段,所以內聯相較宏,是有參數檢查和返回值檢查的,因此使用起來更為安全;

5)需要注意的是, inline會向編譯期提出內聯請求,但是是否內聯由編譯期決定(當然可以通過設置編譯器,強制使用內聯);

6)由於內聯是一種優化方式,在某些情況下,即使沒有顯示的聲明內聯,比如定義在class內部的方法,編譯器也可能將其作為內聯函數。

7)內聯函數不能過於復雜,最初C++限定不能有任何形式的循環,不能有過多的條件判斷,不能對函數進行取地址操作等,但是現在的編譯器幾乎沒有什么限制,基本都可以實現內聯。

9. C++中有了malloc / free , 為什么還需要 new / delete?

1). malloc與free是C++/C語言的標准庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。
2). 對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。
由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free。因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。
最后補充一點體外話,new 在申請內存的時候就可以初始化(如下代碼), 而malloc是不允許的。另外,由於malloc是庫函數,需要相應的庫支持,因此某些簡易的平台可能不支持,但是new就沒有這個問題了,因為new是C++語言所自帶的運算符。

int *p = new int(1);

特別的,在C++中,如下的代碼,用new創建一個對象(new 會觸發構造函數, delete會觸發析構函數),但是malloc僅僅申請了一個空間,所以在C++中引入new和delete來支持面向對象。

#include <cstdlib>
class Test
{
    ...
}

Test* pn = new Test;
Test* pm = (Test*)malloc(sizeof(Test));

10. C和C++中的強制類型轉換?

C中是直接在變量或者表達式前面加上(小括號括起來的)目標類型來進行轉換,一招走天下,操作簡單,但是由於太過直接,缺少檢查,因此容易發生編譯檢查不到錯誤,而人工檢查又及其難以發現的情況;而C++中引入了下面四種轉換:
1)static_cast
用於基本類型間的轉換
不能用於基本類型指針間的轉換
用於有繼承關系類對象間的轉換和類指針間的轉換
2)dynamic_cast
用於有繼承關系的類指針間的轉換
用於有交叉關系的類指針間的轉換
具有類型檢查的功能
需要虛函數的支持
3)reinterpret_cast
用於指針間的類型轉換
用於整數和指針間的類型轉換
4)const_cast
用於去掉變量的const屬性
轉換的目標類型必須是指針或者引用
在C++中,普通類型可以通過類型轉換構造函數轉換為類類型,那么類可以轉換為普通類型嗎?答案是肯定的。但是在工程應用中一般不用類型轉換函數,因為無法抑制隱式的調用類型轉換函數(類型轉換構造函數可以通過explicit來抑制其被隱式的調用),而隱式調用經常是bug的來源。實際工程中替代的方式是定義一個普通函數,通過顯式的調用來達到類型轉換的目的。

class test{
    int m_value;
    ...
public:
    operator int()  //類型轉換函數
    {
        return m_value;
    }

    int toInt() //顯示調用普通函數來實現類型轉換
    {
        return m_value
    }
};

int main()
{
    ...
    test a(5);
    int i = a;
    ...

    return 0;
}

11. 在C++程序中調用被C編譯器編譯后的函數,為什么要加extern“C”?

C++語言支持函數重載,C語言不支持函數重載,函數被C++編譯器編譯后在庫中的名字與C語言的不同,假設某個函數原型為:

 void foo(int x, int y);

該函數被C編譯器編譯后在庫中的名字為 _foo, 而C++編譯器則會產生像: _foo_int_int 之類的名字。為了解決此類名字匹配的問題,C++提供了C鏈接交換指定符號 extern “C”。

三、常見C++面試題

1.子類析構時要調用父類的析構函數嗎?

析構函數調用的次序是先派生類的析構后基類的析構,也就是說在基類的的析構調用的時候,派生類的信息已經全部銷毀了。定義一個對象時先調用基類的構造函數、然后調用派生類的構造函數;析構的時候恰好相反:先調用派生類的析構函數、然后調用基類的析構函數。

2.多態,虛函數,純虛函數

多態:是對於不同對象接收相同消息時產生不同的動作。C++的多態性具體體現在運行和編譯兩個方面:在程序運行時的多態性通過繼承和虛函數來體現;

在程序編譯時多態性體現在函數和運算符的重載上;

虛函數:在基類中冠以關鍵字 virtual 的成員函數。 它提供了一種接口界面。允許在派生類中對基類的虛函數重新定義。

純虛函數的作用:在基類中為其派生類保留一個函數的名字,以便派生類根據需要對它進行定義。作為接口而存在 純虛函數不具備函數的功能,一般不能直接被調用。

從基類繼承來的純虛函數,在派生類中仍是虛函數。如果一個類中至少有一個純虛函數,那么這個類被稱為抽象類(abstract class)。

抽象類中不僅包括純虛函數,也可包括虛函數。抽象類必須用作派生其他類的基類,而不能用於直接創建對象實例。但仍可使用指向抽象類的指針支持運行時多態性。

3.求下面函數的返回值

int func(x) 

{ 

int countx = 0; 

while(x) 

{ 

countx ++; 

x = x&(x-1); 

} 

return countx; 

} 

假定x = 9999。 答案:8

思路:將x轉化為2進制,看含有的1的個數。

4.什么是“引用”?申明和使用“引用”要注意哪些問題?

答:引用就是某個目標變量的“別名”(alias),對引用的操作與對變量直接操作效果完全相同。申明一個引用的時候,切記要對其進行初始化。引用聲明完畢后,相當於目標變量名有兩個名稱,即該目標原名稱和引用名,不能再把該引用名作為其他變量名的別名。聲明一個引用,不是新定義了一個變量,它只表示該引用名是目標變量名的一個別名,它本身不是一種數據類型,因此引用本身不占存儲單元,系統也不給引用分配存儲單元。不能建立數組的引用。

5.將“引用”作為函數參數有哪些特點?

(1)傳遞引用給函數與傳遞指針的效果是一樣的。這時,被調函數的形參就成為原來主調函數中的實參變量或對象的一個別名來使用,所以在被調函數中對形參變量的操作就是對其相應的目標對象(在主調函數中)的操作。

(2)使用引用傳遞函數的參數,在內存中並沒有產生實參的副本,它是直接對實參操作;而使用一般變量傳遞函數的參數,當發生函數調用時,需要給形參分配存儲單元,形參變量是實參變量的副本;如果傳遞的是對象,還將調用拷貝構造函數。因此,當參數傳遞的數據較大時,用引用比用一般變量傳遞參數的效率和所占空間都好。

(3)使用指針作為函數的參數雖然也能達到與使用引用的效果,但是,在被調函數中同樣要給形參分配存儲單元,且需要重復使用"*指針變量名"的形式進行運算,這很容易產生錯誤且程序的閱讀性較差;另一方面,在主調函數的調用點處,必須用變量的地址作為實參。而引用更容易使用,更清晰。

6.將“引用”作為函數返回值類型的格式、好處和需要遵守的規則?

格式:類型標識符 &函數名(形參列表及類型說明){ //函數體 }

好處:在內存中不產生被返回值的副本;(注意:正是因為這點原因,所以返回一個局部變量的引用是不可取的。因為隨着該局部變量生存期的結束,相應的引用也會失效,產生runtime error! 

注意事項:

(1)不能返回局部變量的引用。這條可以參照Effective C++[1]的Item 31。主要原因是局部變量會在函數返回后被銷毀,因此被返回的引用就成為了"無所指"的引用,程序會進入未知狀態。

(2)不能返回函數內部new分配的內存的引用。這條可以參照Effective C++[1]的Item 31。雖然不存在局部變量的被動銷毀問題,可對於這種情況(返回函數內部new分配內存的引用),又面臨其它尷尬局面。例如,被函數返回的引用只是作為一個臨時變量出現,而沒有被賦予一個實際的變量,那么這個引用所指向的空間(由new分配)就無法釋放,造成memory leak。

(3)可以返回類成員的引用,但最好是const。這條原則可以參照Effective C++[1]的Item 30。主要原因是當對象的屬性是與某種業務規則(business rule)相關聯的時候,其賦值常常與某些其它屬性或者對象的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它對象可以獲得該屬性的非常量引用(或指針),那么對該屬性的單純賦值就會破壞業務規則的完整性。

(4)流操作符重載返回值申明為“引用”的作用:

流操作符<<和>>,這兩個操作符常常希望被連續使用,例如:cout << "hello" << endl; 因此這兩個操作符的返回值應該是一個仍然支持這兩個操作符的流引用。可選的其它方案包括:返回一個流對象和返回一個流對象指針。但是對於返回一個流對象,程序必須重新(拷貝)構造一個新的流對象,也就是說,連續的兩個<<操作符實際上是針對不同對象的!這無法讓人接受。對於返回一個流指針則不能連續使用<<操作符。因此,返回一個流對象引用是惟一選擇。這個唯一選擇很關鍵,它說明了引用的重要性以及無可替代性,也許這就是C++語言中引入引用這個概念的原因吧。 

賦值操作符=。這個操作符象流操作符一樣,是可以連續使用的,例如:x = j = 10;或者(x=10)=100;賦值操作符的返回值必須是一個左值,以便可以被繼續賦值。因此引用成了這個操作符的惟一返回值選擇。

#include<iostream.h>

int &put(int n);

int vals[10];

int error=-1;

void main()

{
put(0)=10; //以put(0)函數值作為左值,等價於vals[0]=10; 

put(9)=20; //以put(9)函數值作為左值,等價於vals[9]=20; 

cout<<vals[0]; 

cout<<vals[9];

} 

int &put(int n)

{
if (n>=0 && n<=9 ) return vals[n]; 

else { cout<<"subscript error"; return error; }

}

(5)在另外的一些操作符中,卻千萬不能返回引用:+-*/ 四則運算符。它們不能返回引用,Effective C++[1]的Item23詳細的討論了這個問題。主要原因是這四個操作符沒有side effect,因此,它們必須構造一個對象作為返回值,可選的方案包括:返回一個對象、返回一個局部變量的引用,返回一個new分配的對象的引用、返回一個靜態對象引用。根據前面提到的引用作為返回值的三個規則,2、3兩個方案都被否決了。靜態對象的引用又因為((a+b) == (c+d))會永遠為true而導致錯誤。所以可選的只剩下返回一個對象了。

7.重載(overload)和重寫(overried,有的書也叫做“覆蓋”)的區別?

常考的題目。從定義上來說:

重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數類型不同,或許兩者都不同)。

重寫:是指子類重新定義父類虛函數的方法。

從實現原理上來說:

重載:編譯器根據函數不同的參數表,對同名函數的名稱做修飾,然后這些同名函數就成了不同的函數(至少對於編譯器來說是這樣的)。如,有兩個同名函數:function func(p:integer):integer;和function func(p:string):integer;。那么編譯器做過修飾后的函數名稱可能是這樣的:int_func、str_func。對於這兩個函數的調用,在編譯器間就已經確定了,是靜態的。也就是說,它們的地址在編譯期就綁定了(早綁定),因此,重載和多態無關!

重寫:和多態真正相關。當子類重新定義了父類的虛函數后,父類指針根據賦給它的不同的子類指針,動態的調用屬於子類的該函數,這樣的函數調用在編譯期間是無法確定的(調用的子類的虛函數的地址無法給出)。因此,這樣的函數地址是在運行期綁定的(晚綁定)。

8.描述內存分配方式以及它們的區別?

1) 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static 變量。

2) 在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集。

3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程序員自己負責在何時用free 或delete 釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但問題也最多。

9.請說出const與#define 相比,有何優點

答案:
const作用:定義常量、修飾函數參數、修飾函數返回值三個作用。被Const修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性。

1) const 常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。而對后者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤。

2) 有些集成化的調試工具可以對const 常量進行調試,但是不能對宏常量進行調試。

10.引用與指針有什么區別?                       

1) 引用必須被初始化,指針不必。

2) 引用初始化以后不能被改變,指針可以改變所指的對象。

3) 不存在指向空值的引用,但是存在指向空值的指針。

11.內存的分配方式有幾種?

1)從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量。

2)在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。

3)從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由我們決定,使用非常靈活,但問題也最多。

12.基類的析構函數不是虛函數,會帶來什么問題?

派生類的析構函數用不上,會造成資源的泄漏。

13.全局變量和局部變量有什么區別?是怎么實現的?操作系統和編譯器是怎么知道的?

生命周期不同:

全局變量隨主程序創建和創建,隨主程序銷毀而銷毀;局部變量在局部函數內部,甚至局部循環體等內部存在,退出就不存在;

使用方式不同:通過聲明后全局變量程序的各個部分都可以用到;局部變量只能在局部使用;分配在棧區。 

操作系統和編譯器通過內存分配的位置來知道的,全局變量分配在全局數據段並且在程序開始運行的時候被加載。局部變量則分配在堆棧里面 。

14.const 關鍵字的使用場景

關鍵詞const表示所修飾的變量或指針是常量。const 可以用來定義全局變量、局部變量;被const修飾的變量效果一致,只能在初始化時候賦值。

 

// 1、常量變量
const int a = 3; //初始化時候必須賦值
a = 5; //編譯時候會報錯

// 2、常量指針(指針指向的值不能修改)
const int *a = NULL; //等同於 int const *a = NULL;
int b = 3;
a = &b; //正確
*a = 6; //編譯時候會報錯

// 3、指針常量(指針地址不能修改)
int* const a = NULL;
int b = 10;
*a = 6; //正確
a = &b; //編譯報錯

// 4、如何區分指針常量和常量指針
前提:把const 當做常量,*當作指針
那么:
const * :常量指針
* const :指針常量

c++ 中定義成員函數的時候后面加const。其作用是該函數體內不允許修改類的成員變量。

15.explicit 關鍵字的使用場景

explicit關鍵字只對有一個參數的類構造函數有效, 如果類構造函數參數大於或等於兩個時, 是不會產生隱式轉換的, 所以explicit關鍵字也就無效了

聲明為explicit的構造函數不能在隱式轉換中使用,只能顯示調用,去構造一個類對象。

Base base(‘a’) //顯示調用,OK
Base base = ‘a’ //隱是調用,err

16.智能指針有哪些,實現原理以及用法

先來說一下四種常用的智能指針,我按使用度從低到高排一下順序,分別是:auto_ptr、unique_ptr、shared_ptr、 weak_ptr。

auto_ptr 最顯著的特點就是一個對象的空間只能一個對象用,不可以兩個對象共用同一塊空間,避免了程序崩潰問題,當我們賦值以后我們以前的對象資源就被置空了。
unique_ptr 主要的特點是我們不能進行賦值,拷貝,而我們實現也和auot_ptr簡單的實現原理差不多的,主要是拷貝,賦值函數的私有化,並且在c++98里面我們只聲明不定義。
shared_ptr是通過引用計數的方法管理同一塊內存的,這樣內存什么時候釋放,內存指向會不會成為野指針就知道了。(在線程安全問題)
weak_ptr 和 shared_ptr 兩個智能指針類都公有繼承了一個抽象的引用計數的類,所以,shared_ptr和weak_ptr的實現方式所差無幾,就是二者的引用計數有區別。(雙端隊列節點指針)

17.C++ 內存空間布局

 

 

1)代碼區(text segment):又稱只讀區。通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,並且內存區域通常屬於只讀,某些架構也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數變量,比如字符串常量等。
2)全局初始化數據區/靜態數據區(Data Segment):用來存放程序已經初始化的全局變量,已經初始化的靜態變量。位置位於可執行代碼段后面,可以是不相連的。在程序運行之初就為數據段申請了空間,程序退出的時候釋放空間,其生命周期是整個程序的運行時期。
3)未初始化數據區(BSS):用來存放程序中未初始化的全局變量和靜態變量,位置在數據段之后,可以不相連。其生命周期和數據段一樣。(2)和(3)統稱為靜態存儲區。
4)棧區(Stack):又稱堆棧,存放程序臨時創建的局部變量,如函數的參數值、返回值、局部變量等。也就是我們函數括弧{}中定義的變量(但不包括static聲明的靜態變量,static意味着在數據段中存放的變量)。除此之外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且等到調用結束后,函數的返回值也會被存放回棧中。編譯器自動分配釋放,是向下有限擴展的。
5)堆區(Heap):位於棧區的下面,是向上有限擴展的。用於存放進程運行中動態分配的內存段,它的大小並不固定,可動態擴張或縮減。當進程調用malloc等函數分配內存的時候,新分配的內存就被動態添加到堆上(堆被擴張);當利用free等函數釋放內存的時候,被釋放的內存從堆中被剔除(堆被縮減)。一般由程序員進行分配和釋放,若不釋放,在程序結束的時候,由OS負責回收。
const修飾的全局變量保存在代碼區中,const修飾的局部變量保存在棧段中。

18.如何限制對象只能在堆上創建

動態建立類對象,是使用 new 運算符將對象建立在堆空間中。這個過程分為兩步,第一步是執行 operator new() 函數,在堆空間中搜索合適的內存並進行分配;第二步是調用構造函數構造對象,初始化這片內存空間。這種方法,間接調用類的構造函數。

將析構函數設為私有,類對象就無法建立在棧上了

19.更多阿里、百度、華為、美團、騰訊、頭條C++面試題可以關注微信公眾號“C和C加加”回復“面試題”即可獲取相關C++面試題!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM