static 關(guān)鍵字的作用
1 全局靜態(tài)變量
在全局變量前加上關(guān)鍵字static,全局變量就定義成一個(gè)全局靜態(tài)變量。
靜態(tài)存儲(chǔ)區(qū),在整個(gè)程序運(yùn)行期間一直存在。
初始化:未經(jīng)初始化的全局變量會(huì)被自動(dòng)初始化為0;
作用域:全局靜態(tài)變量在聲明他的文件之外是不可見的,準(zhǔn)確的說是從定義之處開始到結(jié)尾;
2 局部靜態(tài)變量
在局部變量之前加上關(guān)鍵字static 就變成了局部靜態(tài)變量
3 靜態(tài)函數(shù)
在函數(shù)返回類型前加static,函數(shù)定義就為靜態(tài)函數(shù),函數(shù)的定義和聲明都是extrm,但是靜態(tài)函數(shù)在聲明他的文件夾下可以見,其他地方不能使用
C 和 C++ 的區(qū)別
C++是面向?qū)ο蟮恼Z言,而C是面向過程的結(jié)構(gòu)化編程語言
語法上:
C++具有重載,繼承和多態(tài)
C++比C多了很多類型的安全功能,比如強(qiáng)制類型轉(zhuǎn)換
C++支持范式編程,比如模板類,函數(shù)模板之類
C++四種cast轉(zhuǎn)換
C++的四種轉(zhuǎn)換是:static_cast dynamic_cast const_cast reinterpret_cast
const_cast?
用于將const變量轉(zhuǎn)換為非const
static_cast?
用于各種隱式轉(zhuǎn)換,比如非const轉(zhuǎn)換為非const? void*指針轉(zhuǎn)換 static_const能用于多態(tài)向上轉(zhuǎn)換,如果向下轉(zhuǎn)能成功但是不安全。
dynamic_cast?
用于動(dòng)態(tài)類型轉(zhuǎn)換,只能用于含有虛函數(shù)的類,用于類層次的向上和向下轉(zhuǎn)換,只能轉(zhuǎn)指針或者引用。如向下轉(zhuǎn)化時(shí),如果是非法的對(duì)于指針返回NULL,對(duì)于引用拋出異常
reinterpret_cast
什么都能轉(zhuǎn) 比如int轉(zhuǎn)指針
說一下C/C++中指針和引用的區(qū)別
1 指針是有自己的一塊空間 而引用只是一個(gè)別名
2 使用sizeof看一個(gè)指針的大小是4,而引用則是被引用對(duì)象的大小
3 指針是可以被初始化為NULL 而引用必須被初始化且必須是一個(gè)已有對(duì)象的引用
4 作為參數(shù)傳遞時(shí),指針需要被解引用才可以對(duì)對(duì)象進(jìn)行操作 而直接引用的修改會(huì)改變被引用的對(duì)象
5 可以有const指針,但是沒有const引用
6 指針在使用中可以指向其他對(duì)象,但是引用只能是一個(gè)對(duì)象的引用,不能被改變
7 指針可以有多級(jí)指針(**p)? 而引用只能是一級(jí)的
8 指針和引用使用++符號(hào)意義不一樣
9 如果返回動(dòng)態(tài)內(nèi)存分配的對(duì)象或者內(nèi)存,必須使用指針,引用可能引起內(nèi)存的泄露
請(qǐng)你說下你理解的C++中的smart pointer 四個(gè)智能指針:
為什么要使用智能指針:
智能指針的作用是管理一個(gè)指針,因?yàn)榇嬖谝韵逻@種情況:申請(qǐng)的空間在函數(shù)結(jié)束的時(shí)候忘記釋放掉,造成內(nèi)存泄露。
使用智能指針能很大程度上避免這個(gè)問題,因?yàn)橹悄苤羔樉褪且粋€(gè)類,當(dāng)超出了類的作用域時(shí),類會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),析構(gòu)函數(shù)會(huì)自動(dòng)釋放資源,所以智能函數(shù)能自動(dòng)釋放空間,不需要手動(dòng)釋放內(nèi)存。
unique_ptr (替換auto_ptr)
unique_ptr 實(shí)現(xiàn)獨(dú)占式擁有或者嚴(yán)格擁有概念,保證同一時(shí)間內(nèi)只有一個(gè)智能指針可以指向該對(duì)象,它可以避免資源泄露
采用所有權(quán)模式,還是上面那個(gè)例子
unique_ptr<string> p3 (newstring ("auto")); ??//#4
unique_ptr<string> p4; ??????????????????????//#5
p4 = p3;//此時(shí)會(huì)報(bào)錯(cuò)!!
編譯器會(huì)認(rèn)為p4=p3非法,避免了p3不再指向有效數(shù)據(jù)的問題。因此unique_ptr幣auto_ptr更加安全
另外unique_ptr還有更加聰明的地方,當(dāng)程序試圖將一個(gè)unique_ptr賦值給另一個(gè)時(shí) ,如果源unique_ptr 是個(gè)臨時(shí)右值,編譯器允許這么做;如果unique_ptr將存在一段時(shí)間,編譯器將禁止那樣做
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1; ?????????????????????????????????????// #1 not allowed
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You")); ??// #2 allowed
shared_ptr?
shared_ptr 實(shí)現(xiàn)了共享式擁有概念。多個(gè)智能指針可以指向相同對(duì)象,該對(duì)象和其他相關(guān)資源會(huì)在最后一個(gè)引用時(shí)被銷毀時(shí)釋放。
從名字share就可以看出資源可以被多個(gè)指針共享,他使用記數(shù)機(jī)制來表名資源被幾個(gè)指針共享??梢酝ㄟ^成員函數(shù)use_count()來查看資源使用者個(gè)數(shù),除了可以通過new來構(gòu)造,還可以通過auto_ptr ,unique_ptr來構(gòu)造,當(dāng)我們來調(diào)用release()時(shí),當(dāng)前指針會(huì)釋放所有權(quán),計(jì)數(shù)減1 當(dāng)計(jì)數(shù)等于0的時(shí)候,資源會(huì)被釋放。
share_ptr是為了解決auto_ptr 在對(duì)象所有權(quán)上的局限性,在使用引用計(jì)數(shù)的機(jī)制上提供了可以共享所有權(quán)的智能指針。
成員函數(shù)
use_count 返回引用計(jì)數(shù)個(gè)數(shù)
unique返回是否是獨(dú)占所有權(quán)
swap交換兩個(gè)shared_ptr對(duì)象
reset放棄內(nèi)部對(duì)象的所有權(quán)或擁有對(duì)象的變更,會(huì)引起原有對(duì)象的引用計(jì)數(shù)的減少
get返回內(nèi)部對(duì)象指針,由于已經(jīng)重載()方法,因此和直接使用對(duì)象是一樣的,如shared_ptr<int> sp(new int(1)); sp與sp.get()等價(jià)的
weak_ptr?
weak_ptr 是一種不控制對(duì)象生命周期的智能指針, 它指向一個(gè) shared_ptr 管理的對(duì)象. 進(jìn)行該對(duì)象的內(nèi)存管理的是那個(gè)強(qiáng)引用的 shared_ptr. weak_ptr只是提供了對(duì)管理對(duì)象的一個(gè)訪問手段。weak_ptr 設(shè)計(jì)的目的是為配合 shared_ptr 而引入的一種智能指針來協(xié)助 shared_ptr 工作, 它只可以從一個(gè) shared_ptr 或另一個(gè) weak_ptr 對(duì)象構(gòu)造, 它的構(gòu)造和析構(gòu)不會(huì)引起引用記數(shù)的增加或減少。weak_ptr是用來解決shared_ptr相互引用時(shí)的死鎖問題,如果說兩個(gè)shared_ptr相互引用,那么這兩個(gè)指針的引用計(jì)數(shù)永遠(yuǎn)不可能下降為0,資源永遠(yuǎn)不會(huì)釋放。它是對(duì)對(duì)象的一種弱引用,不會(huì)增加對(duì)象的引用計(jì)數(shù),和shared_ptr之間可以相互轉(zhuǎn)化,shared_ptr可以直接賦值給它,它可以通過調(diào)用lock函數(shù)來獲得shared_ptr。
● 怎么判斷一個(gè)數(shù)是二的倍數(shù),怎么求一個(gè)數(shù)中有幾個(gè)1,說一下你的思路并手寫代碼
1 判斷一個(gè)數(shù)是不是二的倍數(shù),即判斷該數(shù)二位進(jìn)制末位是不是0
a % 2 == 0 或者a & 0x0001 == 0。
2、求一個(gè)數(shù)中1的位數(shù),可以直接逐位除十取余判斷:
int fun(long x)
{
int _count =?0;
while(x)
{
if(x %?10==?1)
++_count;
x /=?10;
}
return _count;
}
int main()
{
cout << fun(123321) << endl;
return?0;
}
請(qǐng)回答一下數(shù)組和指針的區(qū)別
參考答案:
指針:
保存數(shù)據(jù)地址
間接訪問數(shù)據(jù),首先獲得指針的內(nèi)容,然后將其作為地址,從該地址中提取數(shù)據(jù)
通常用于動(dòng)態(tài)的數(shù)據(jù)結(jié)構(gòu)
通過Malloc分配內(nèi)存,free釋放內(nèi)存
通常指向匿名數(shù)據(jù),操作匿名函數(shù)
數(shù)組:
保存數(shù)據(jù)
直接訪問數(shù)據(jù)
通常用于固定的數(shù)目且數(shù)據(jù)類型相同的元素
隱式的分配和刪除
自身就為數(shù)據(jù)名
請(qǐng)回答下什么是野指針
野指針就是指向已經(jīng)刪除的對(duì)象或者未申請(qǐng)?jiān)L問受限的內(nèi)存區(qū)域的指針
請(qǐng)你介紹下C++中的智能指針
智能指針主要管理在堆上分配的內(nèi)存,他講普通的的指針封裝為一個(gè)棧對(duì)象。當(dāng)棧對(duì)象的生存周期結(jié)束后,會(huì)在析構(gòu)函數(shù)中釋放掉申請(qǐng)的內(nèi)存,從而防止內(nèi)存泄露。
C++中常用的智能指針類型為shared_ptr,他采用引用計(jì)數(shù)的方法,記錄當(dāng)前內(nèi)存資源被多少個(gè)智能指針引用。該引用計(jì)數(shù)的內(nèi)存在堆上分配,當(dāng)新增一個(gè)時(shí)引用計(jì)數(shù)加1,當(dāng)過期時(shí)引用計(jì)數(shù)減1。只有引用計(jì)數(shù)為0時(shí),智能指針才會(huì)自動(dòng)釋放引用的內(nèi)存資源。對(duì)shared_ptr進(jìn)行初始化時(shí)不能將一個(gè)普通指針直接賦值給智能指針,因?yàn)橐粋€(gè)是指針一個(gè)是類。
● 請(qǐng)你來說一下智能指針的內(nèi)存泄漏如何解決
為了解決循環(huán)引用導(dǎo)致的內(nèi)存泄露,引入了weak_ptr 弱指針,weak_ptr 的構(gòu)造函數(shù)不會(huì)修改引用計(jì)數(shù)的值,從而不會(huì)對(duì)對(duì)象的內(nèi)存進(jìn)行管理,其類似的一個(gè)普通的指針,但不能引用計(jì)數(shù)的共享內(nèi)存,但是可以檢測(cè)到所管理的對(duì)象是否已經(jīng)被釋放,從而避免非法訪問
● 請(qǐng)你回答一下為什么析構(gòu)函數(shù)必須是虛函數(shù)?為什么C++默認(rèn)的析構(gòu)函數(shù)不是虛函數(shù) 考點(diǎn):虛函數(shù) 析構(gòu)函數(shù)
將可能會(huì)被繼承的父類的析構(gòu)函數(shù)設(shè)置為虛函數(shù),可以保證我們new一個(gè)子類,然后使用基類指針指向該子類對(duì)象,釋放掉基類的指針可以釋放掉子類的空間,防止內(nèi)存泄露。
C++默認(rèn)的析構(gòu)函數(shù)不是虛函數(shù)是因?yàn)樘摵瘮?shù)需要額外的虛函數(shù)表和虛表指針,占用額外的內(nèi)存,而對(duì)于不會(huì)繼承的類來說,其虛函數(shù),就會(huì)浪費(fèi)內(nèi)存。因此C++默認(rèn)的析構(gòu)函數(shù)不是虛函數(shù),而是只有當(dāng)需要當(dāng)做父類的時(shí)候,設(shè)置為虛函數(shù)
● 請(qǐng)你來說一下函數(shù)指針
1 定義
函數(shù)指針是指向函數(shù)的指針變量
函數(shù)指針本身是一個(gè)指針變量,該指針變量指向一個(gè)具體的函數(shù)。這正如用指針變量可指向整型變量,字符型,這里是指向函數(shù)。
C在編譯時(shí),每一個(gè)函數(shù)都有一個(gè)入口地址,該入口地址就是函數(shù)指針?biāo)赶虻牡刂?,有了指向函?shù)的指針變量后,可用該指針變量調(diào)用函數(shù),就如同用指針變量可引用其他類型變量一樣
2 用途
調(diào)用函數(shù)和做函數(shù)的參數(shù),比如回調(diào)函數(shù)。
3 示例
char?* fun(char?* p) ?{…} ??????// 函數(shù)fun
char?* (*pf)(char?* p);?????????????// 函數(shù)指針pf
pf = fun;????????????????????????// 函數(shù)指針pf指向函數(shù)fun
pf(p);????????????????????????// 通過函數(shù)指針pf調(diào)用函數(shù)fun
● 請(qǐng)你來說一下fork函數(shù)
fork:創(chuàng)建一個(gè)和當(dāng)前進(jìn)程映像一樣的進(jìn)程可以通過fork()系統(tǒng)調(diào)用:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
成功的調(diào)用fork 會(huì)創(chuàng)建一個(gè)新的進(jìn)程,他幾乎與調(diào)用fork()的進(jìn)程一模一樣,這兩個(gè)進(jìn)程都會(huì)繼續(xù)進(jìn)行,在子進(jìn)程中,成功的fork()調(diào)用會(huì)返回0,在父進(jìn)程中fork()返回子進(jìn)程的pid,如果出現(xiàn)錯(cuò)誤,fork() 返回一個(gè)負(fù)值
最常見的fork()用法是創(chuàng)建一個(gè)新的進(jìn)程,然后使用exec()載入二進(jìn)制映像,替換當(dāng)前進(jìn)程的映像,在這種情況下,派生(fork)了新的進(jìn)程,而這個(gè)子進(jìn)程會(huì)執(zhí)行一個(gè)新的二進(jìn)制可執(zhí)行文件的映像,這種派生加執(zhí)行的方式是很常見的。
在早期Unix系統(tǒng)中,創(chuàng)建進(jìn)程比較原始。當(dāng)調(diào)用fork()時(shí),內(nèi)核會(huì)把所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)賦值一份,復(fù)制進(jìn)程的頁(yè)表項(xiàng),然后把父進(jìn)程的地址空間中的內(nèi)容逐頁(yè)復(fù)制到子進(jìn)程地址空間中,但從內(nèi)核角度來看,逐頁(yè)的復(fù)制方法十分耗時(shí),
● 請(qǐng)你來說一下C++中析構(gòu)函數(shù)的作用
析構(gòu)函數(shù)與構(gòu)造函數(shù)對(duì)應(yīng),當(dāng)對(duì)象結(jié)束其生命周期,如對(duì)象所在的函數(shù)已調(diào)用完畢時(shí),系統(tǒng)會(huì)自動(dòng)執(zhí)行析構(gòu)函數(shù)。
析構(gòu)函數(shù)名與類函數(shù)名相同,只是在函數(shù)名前加一個(gè)位取反符~??
例如~stud()以區(qū)別構(gòu)造函數(shù),他不能帶任何參數(shù),也沒有返回值,(包括void類型)。
只能有一個(gè)析構(gòu)函數(shù)不能重載。
如果用戶沒有編寫析構(gòu)函數(shù),編譯系統(tǒng)會(huì)自動(dòng)生成一個(gè)缺省的析構(gòu)函數(shù)(即自定義了析構(gòu)函數(shù))編譯器總是會(huì)為我們合成一個(gè)析構(gòu)函數(shù),并且自定義了析構(gòu)函數(shù),編譯器在執(zhí)行時(shí)會(huì)先調(diào)用自定義的析構(gòu)函數(shù)再調(diào)用合成的析構(gòu)函數(shù),他也不進(jìn)行任何操作。所以許多簡(jiǎn)單的類中,沒有用顯示的析構(gòu)函數(shù)。
如果一個(gè)類中有指針,并且在使用過程中動(dòng)態(tài)的申請(qǐng)了內(nèi)存,那么最好顯示構(gòu)造函數(shù)在銷毀類之前,釋放掉申請(qǐng)的內(nèi)存空間,避免內(nèi)存泄露。
類析構(gòu)順序:1)派生類本身的析構(gòu)函數(shù);2)對(duì)象成員析構(gòu)函數(shù);3)基類析構(gòu)函數(shù)。
● 請(qǐng)你來說一下靜態(tài)函數(shù)和虛函數(shù)的區(qū)別
靜態(tài)函數(shù)在編譯的時(shí)候就已經(jīng)確定運(yùn)行時(shí)機(jī),虛函數(shù)在運(yùn)行的時(shí)候動(dòng)態(tài)綁定,虛函數(shù)因?yàn)橛昧颂摵瘮?shù)表機(jī)制,調(diào)用的時(shí)候會(huì)增加一次內(nèi)存開銷;
● 請(qǐng)你來說一說重載和覆蓋
重載:兩個(gè)函數(shù)名相同,但是參數(shù)列表不同,(個(gè)數(shù),類型)返回值類型沒有要求,在同一作用域中;
重寫: 子類繼承父類,父類中的函數(shù)是虛函數(shù),在子類中重新定義了這個(gè)虛函數(shù),這種情況是重寫;
● 請(qǐng)你來說一說static關(guān)鍵字
1 加了static關(guān)鍵字的全局變量只能在本文件中使用,
2 static定義的靜態(tài)局部變量分配在數(shù)據(jù)段上,普通的局部變量分配在棧上,會(huì)因?yàn)楹瘮?shù)棧幀的釋放而被釋放掉
3 對(duì)一個(gè)類中成員變量和成員函數(shù)來書,加了static關(guān)鍵字后就必須通過類名才能訪問;
● 請(qǐng)你說一說strcpy和strlen
strcpy是字符串拷貝函數(shù),原型:
char *strcpy(char* dest, const char *src);
從src逐字拷貝到dest,直到遇到‘/0’結(jié)束,因?yàn)闆]有指定的長(zhǎng)度,可能會(huì)導(dǎo)致拷貝越界,造成緩沖區(qū)溢出漏洞,安全版本是strncpy函數(shù)。
strlen是計(jì)算字符串長(zhǎng)度的函數(shù),返回從開始到‘/0’之間的字符串個(gè)數(shù)
● 請(qǐng)你說一說你理解的虛函數(shù)和多態(tài)
多態(tài)的感覺主要分為靜態(tài)多態(tài)和動(dòng)態(tài)多態(tài),靜態(tài)多態(tài)主要是重載,在編譯時(shí)就已經(jīng)確定了;動(dòng)態(tài)多態(tài)是虛函數(shù)機(jī)制實(shí)現(xiàn)的,在運(yùn)行期間動(dòng)態(tài)綁定。舉個(gè)列子,一個(gè)父類型的函數(shù)指向一個(gè)子類對(duì)象的時(shí)候,會(huì)調(diào)用子類重寫過后的函數(shù),在父類中聲明為加了virtual關(guān)鍵字,在子類中不加virtual也是虛函數(shù);
虛函數(shù)的實(shí)現(xiàn),在有虛函數(shù)的類中,類的最開始部分是一個(gè)虛函數(shù)表的指針,這個(gè)指針指向一個(gè)虛函數(shù)表,表中放了虛函數(shù)的地址,實(shí)際的虛函數(shù)在代碼段中。當(dāng)子類繼承父類的時(shí)候也會(huì)繼承虛函數(shù)表,當(dāng)子類重寫父類的虛函數(shù)的時(shí)候,會(huì)將繼承到的虛函數(shù)表的地址替換為重寫寫的函數(shù)地址,使用虛函數(shù)會(huì)增加訪問內(nèi)存的開銷,降低效率。
請(qǐng)你回答下++i和i++的區(qū)別
++i先自增1,再返回;
i++是先返回,再自增1
● 請(qǐng)你來寫個(gè)函數(shù)在main函數(shù)執(zhí)行前先運(yùn)行
__attribute((constructor))void before()
{
????printf("before main\n");
}
● 有段代碼寫成了下邊這樣,如果在只修改一個(gè)字符的前提下,使代碼輸出20個(gè)hello? for(int i = 0; i < 20; i--) cout << "hello" << endl;
for(int i = 0; i + 20; i--)
cout <<?"hello"<< endl;
● 以下四行代碼的區(qū)別是什么? const char * arr = "123"; char * brr = "123"; const char crr[] = "123"; char drr[] = "123";
const char * arr = "123";
字符串123 保存在常量區(qū),const本來是修飾arr指向的值不能通過arr去修改,但是字符串在常量區(qū),本來就不能改變,所以加不加const都一樣,
char * brr = "123";
字符串123 保存在常量區(qū),這個(gè)arr指針指向的是同一個(gè)位置,同樣不能通過brr修改123的值
const char crr[] = "123";
這里123是在棧上,但是編譯器可能會(huì)做某些優(yōu)化,將其放在常量區(qū);
char drr[] = "123";
字符串保存在棧區(qū) 但是可以通過drr來修改
● 請(qǐng)你來說一下C++里是怎么定義常量的?常量存放在內(nèi)存的哪個(gè)位置?
常量在C++里的定義就是一個(gè)top-level const 加上對(duì)象類型,常量定義必須初始化。對(duì)于局部對(duì)象,常量存放在棧中,對(duì)于全局對(duì)象,常量存放在全局/靜態(tài)存儲(chǔ)區(qū)。對(duì)于字面值常量,常量存放在常量存儲(chǔ)區(qū);
● 請(qǐng)你來回答一下const修飾成員函數(shù)的目的是什么?
const修飾的成員函數(shù)表明函數(shù)調(diào)用不會(huì)對(duì)對(duì)象做出任何改變,事實(shí)上,如果對(duì)對(duì)象做出更改,就應(yīng)該為函數(shù)加上const限定,這樣無論是const對(duì)象還是普通對(duì)象都可以調(diào)用函數(shù)。
● 如果同時(shí)定義了兩個(gè)函數(shù),一個(gè)帶const,一個(gè)不帶,會(huì)有問題嗎?
不會(huì) 相當(dāng)于函數(shù)的重載
● 請(qǐng)你來說一說隱式類型轉(zhuǎn)換
首先,對(duì)于內(nèi)置類型,低精度變量給高精度變量賦值會(huì)發(fā)生隱式類型轉(zhuǎn)換,其次對(duì)于只存在單個(gè)參數(shù)的構(gòu)造函數(shù)的對(duì)象構(gòu)造來說,函數(shù)的調(diào)用可以直接使用該參數(shù)的傳入,編譯器會(huì)自動(dòng)調(diào)用其構(gòu)造函數(shù)生成的臨時(shí)對(duì)象;
● 請(qǐng)你來說一說C++函數(shù)??臻g的最大值
默認(rèn)是1M 不過可以調(diào)整
● 請(qǐng)你來說一說extern“C”
首先 new/delete 是C++的關(guān)鍵字 而malloc/free 是C的庫(kù)函數(shù),后者使用必須指明申請(qǐng)的內(nèi)存空間的大小,對(duì)于類類型的對(duì)象,后者不會(huì)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)。
● 請(qǐng)你說說你了解的RTTI
在運(yùn)行時(shí)進(jìn)行檢查,在C++ 層面上主要體現(xiàn)在dynamic_cast 和 typeid.VS中虛函數(shù)表的-1位置存放指向的type_info 的指針,對(duì)于存在虛函數(shù)的類型,typeid和dynamic_cast 都會(huì)去查詢type_info?
● 請(qǐng)你說說虛函數(shù)表具體是怎樣實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)的?
子類若重寫父類的虛函數(shù),虛函數(shù)在表中,該函數(shù)的地址會(huì)被替換,對(duì)于存在虛函數(shù)的類的對(duì)象,在VS中,對(duì)象的對(duì)象模型的頭部存放指向虛函數(shù)表的指針,通過該機(jī)制實(shí)現(xiàn)多態(tài)
● 請(qǐng)你說說C語言是怎么進(jìn)行函數(shù)調(diào)用的?
每個(gè)函數(shù)調(diào)用都會(huì)分配函數(shù)棧,在棧內(nèi)進(jìn)行函數(shù)還行過程。調(diào)用前,先把返回地址壓棧,然后把當(dāng)前函數(shù)的esp指針壓棧;
● 請(qǐng)你說說C語言參數(shù)壓棧順序?
從右到左
● 請(qǐng)你說說C++如何處理返回值?
生成一個(gè)臨時(shí)變量,把他的引用作為函數(shù)參數(shù)傳入函數(shù)內(nèi)
● 請(qǐng)你回答一下C++中拷貝賦值函數(shù)的形參能否進(jìn)行值傳遞?
不能,如果是在這樣的情況下,調(diào)用拷貝構(gòu)造函數(shù)的時(shí)候,首先要將實(shí)參傳遞給形參,這個(gè)傳遞的時(shí)候又要調(diào)用拷貝函數(shù)
如此循環(huán)無法完成拷貝,棧也會(huì)滿
● 請(qǐng)你回答一下malloc與new區(qū)別
malloc 需要給定申請(qǐng)內(nèi)存的大小,返回指針需要強(qiáng)轉(zhuǎn)
new會(huì)調(diào)用構(gòu)造函數(shù),不用指定內(nèi)存大小,返回的指針不用強(qiáng)轉(zhuǎn)
● 請(qǐng)你說一說select
select 在使用之前,先將需要監(jiān)控的描述符對(duì)應(yīng)的bit位置為1,然后將其傳給select,當(dāng)有任何一個(gè)事件發(fā)生時(shí),select將會(huì)返回所有的描述符,需要在應(yīng)用程序自己遍歷去檢查哪個(gè)描述符上有事件發(fā)生 ,效率很低,并且不斷在內(nèi)核態(tài)和用戶態(tài)進(jìn)行描述符的拷貝,開銷很大
● 請(qǐng)你說說fork,wait,exec函數(shù)
父進(jìn)程產(chǎn)生子進(jìn)程使用fork拷貝出來一個(gè)父進(jìn)程的副本,此時(shí)之拷貝了父進(jìn)程的頁(yè)表,兩個(gè)進(jìn)程都讀同一塊內(nèi)存,當(dāng)有進(jìn)程寫的時(shí)候使用寫實(shí)拷貝機(jī)制分配內(nèi)存,exec函數(shù)可以加載一個(gè)elf文件去替換父進(jìn)程,從此父進(jìn)程和子進(jìn)程就可以運(yùn)行不同的程序了,fork從父進(jìn)程返回子進(jìn)程的pid,從子進(jìn)程返回0,調(diào)用了wait的父進(jìn)程將會(huì)放生阻塞,直到有子進(jìn)程狀態(tài)的改變,執(zhí)行成功返回0,錯(cuò)誤返回-1,exec執(zhí)行成功則子進(jìn)程從新的程序開始運(yùn)行,無返回值,執(zhí)行失敗返回-1
● 請(qǐng)你回答一下靜態(tài)函數(shù)和虛函數(shù)的區(qū)別
靜態(tài)函數(shù)在編譯的時(shí)候就已經(jīng)確定運(yùn)行時(shí)機(jī),虛函數(shù)在運(yùn)行的時(shí)候動(dòng)態(tài)綁定。虛函數(shù)因?yàn)橛昧颂摵瘮?shù)表機(jī)制,調(diào)用的時(shí)候會(huì)增加一次內(nèi)存開銷
● 請(qǐng)你說一說重載和覆蓋
重載:兩個(gè)函數(shù)名相同,但是參數(shù)列表不同(個(gè)數(shù),類型)返回值類型沒有要求,在同一作用域中;
重寫:子類繼承父類,父類中的函數(shù)是虛函數(shù),在子類中重新定義了這個(gè)虛函數(shù),這種情況是重寫