?復(fù)習(xí)整理:C/C++區(qū)別與聯(lián)系念搬;
關(guān)于C和C++的區(qū)別是面試中經(jīng)常會(huì)被問到的問題久信,本著即將面試的心態(tài),進(jìn)行知識(shí)整理角骤,并對(duì)小知識(shí)點(diǎn)進(jìn)行擴(kuò)展;
C/C++的聯(lián)系:
C++是C的超集心剥,兼容大部分C的語法的結(jié)構(gòu)邦尊;
聯(lián)系嘛我只能想到這個(gè),畢竟cplusplus嘛优烧!
C/C++區(qū)別:
第一點(diǎn)就應(yīng)該想到C是面向過程的語言蝉揍,而C++是面向?qū)ο蟮恼Z言,一般簡(jiǎn)歷上第一條都是熟悉C/C++基本語法畦娄,了解C++面向?qū)ο笏枷胗终矗敲幢滓牵?qǐng)問什么是面向?qū)ο螅?/p>
C和C++動(dòng)態(tài)管理內(nèi)存的方法不一樣,C是使用malloc/free函數(shù)杖刷,而C++除此之外還有new/delete關(guān)鍵字励饵;(關(guān)于malooc/free與new/delete的不同又可以說一大堆,最后的擴(kuò)展_1部分列出十大區(qū)別)滑燃;
接下來就不得不談到C中的struct和C++的類役听,C++的類是C所沒有的,但是C中的struct是可以在C++中正常使用的表窘,并且C++對(duì)struct進(jìn)行了進(jìn)一步的擴(kuò)展典予,使struct在C++中可以和class一樣當(dāng)做類使用,而唯一和class不同的地方在于struct的成員默認(rèn)訪問修飾符是public,而class默認(rèn)的是private;
C++支持函數(shù)重載乐严,而C不支持函數(shù)重載瘤袖,而C++支持重載的依仗就在于C++的名字修飾與C不同,例如在C++中函數(shù)int fun(int ,int)經(jīng)過名字修飾之后變?yōu)?_fun_int_int ,而C是
_fun昂验,一般是這樣的捂敌,所以C++才會(huì)支持不同的參數(shù)調(diào)用不同的函數(shù);
C++中有引用凛篙,而C沒有黍匾;這樣就不得不提一下引用和指針的區(qū)別(文后擴(kuò)展_2);
當(dāng)然還有C++全部變量的默認(rèn)鏈接屬性是外鏈接,而C是內(nèi)連接呛梆;
C 中用const修飾的變量不可以用在定義數(shù)組時(shí)的大小,但是C++用const修飾的變量可以(如果不進(jìn)行&,解引用的操作的話磕诊,是存放在符號(hào)表的填物,不開辟內(nèi)存);
當(dāng)然還有局部變量的聲明規(guī)則不同霎终,多態(tài)滞磺,C++特有輸入輸出流之類的,很多莱褒,下面就不再列出來了击困; “`
小知識(shí)點(diǎn)補(bǔ)充擴(kuò)展
C/C++學(xué)習(xí)交流QQ群728483370,大家一起加油广凸!
擴(kuò)展_1: 細(xì)數(shù)malloc/free和new/delete的十點(diǎn)區(qū)別
malloc是從堆上開辟空間阅茶,而new是從自由存儲(chǔ)區(qū)開辟;(自由存儲(chǔ)區(qū)是
C++抽象出來的概念谅海,不僅可以是堆脸哀,還可以是靜態(tài)存儲(chǔ)區(qū));
malloc/free是函數(shù)扭吁,而new/delete是關(guān)鍵字撞蜂;
malloc對(duì)開辟的空間大小需要嚴(yán)格指定盲镶,而new只需要對(duì)象名;
malloc開辟的空間即可以給單個(gè)對(duì)象用也可以給數(shù)組用蝌诡,釋放的方式都是
free()溉贿;而new開辟對(duì)象數(shù)組用的是new[size] ,釋放的的時(shí)候是 delete[]
(盡管內(nèi)置類型可能不會(huì)引起問題,但是自定義類型的話浦旱,delete[]需要知道有
多少個(gè)對(duì)象顽照,而這個(gè)計(jì)數(shù)就被放在這塊空間的頭部);
返回值問題,malloc開辟成功返回void*闽寡,需要強(qiáng)轉(zhuǎn)代兵,失敗返回NULL,new
成功返回對(duì)象指針爷狈,失敗拋出異常(這就可能會(huì)提到C++的new_handler機(jī)
制)植影,雖然為了最大程度的兼容C,C++的new也支持失敗返回NULL涎永,但是一般不
被使用思币,大家可以了解一下;
是否調(diào)用構(gòu)造和析構(gòu)羡微,這點(diǎn)應(yīng)該放在前面谷饿,new和free不但負(fù)責(zé)開辟空間,
還會(huì)調(diào)用對(duì)象的構(gòu)造函數(shù)和析構(gòu)函數(shù)妈倔;最好了解一下new的三種表達(dá)形式(new運(yùn)
算符博投,operator new(); placement new();)還有定位new表達(dá)式的
使用;
是否可以相互調(diào)用盯蝴,new的實(shí)現(xiàn)可以用malloc毅哗,malloc的實(shí)現(xiàn)不可以使用
new;
是否可以被重載捧挺,我們可以重載自己的operator new/delete虑绵,但是不可
以重載new/delete/malloc/free;
malloc開辟 的內(nèi)存如果太小,想要換一塊大一點(diǎn)的闽烙,可以調(diào)用relloc實(shí)
現(xiàn)翅睛,但是new沒有直觀的方法來改變;
第十點(diǎn)其實(shí)前面已經(jīng)提到黑竞,當(dāng)new中的底層實(shí)現(xiàn)如果獲取不到更多的內(nèi)存捕发,
會(huì)觸發(fā)new_handler機(jī)制,留有一個(gè)set_new_handler句柄摊溶,看看用戶是否設(shè)
置了這個(gè)句柄爬骤,如果設(shè)置了就去執(zhí)行,句柄的目的是看看能不能嘗試著從操作系
統(tǒng)釋放點(diǎn)內(nèi)存莫换,找點(diǎn)內(nèi)存霞玄,如果實(shí)在不行就拋出bad_alloc異常骤铃;而malloc就
沒有這種嘗試了;——-
擴(kuò)展_2 指針和引用的區(qū)別
1.指針有自己的一塊空間坷剧,而引用只是一個(gè)別名惰爬;
2.使用sizeof看一個(gè)指針的大小是4,而引用則是被引用對(duì)象的大斜蛊蟆撕瞧;
3.指針可以被初始化為NULL,而引用必須被初始化且必須是一個(gè)已有對(duì)象
的引用狞尔;
4.作為參數(shù)傳遞時(shí)丛版,指針需要被解引用才可以對(duì)對(duì)象進(jìn)行操作,而直接對(duì)引
用的修改都會(huì)改變引用所指向的對(duì)象偏序;
5.可以有const指針页畦,但是沒有const引用;
6.指針在使用中可以指向其它對(duì)象研儒,但是引用只能是一個(gè)對(duì)象的引用豫缨,不能
被改變;
7.指針可以有多級(jí)指針(**p)端朵,而引用至于一級(jí)好芭;
8.指針和引用使用++運(yùn)算符的意義不一樣;
擴(kuò)展_3 常見關(guān)鍵字的作用
**1.static 關(guān)鍵字:**
? ? 修飾全局變量時(shí)冲呢,會(huì)將變量的鏈接屬性變?yōu)閮?nèi)部鏈接屬性舍败,并且變量
? ? 的存儲(chǔ)位置變?yōu)槿朱o態(tài)區(qū);
? ? 修飾 局部變量碗硬,改變局部變量的存儲(chǔ)位置為靜態(tài)存儲(chǔ)區(qū)瓤湘,改變局部變
? ? 量的生命周期為整個(gè)程序開始到結(jié)束;
? ? 修飾類的成員變量和函數(shù):屬于類而不屬于對(duì)象恩尾,屬于所有實(shí)例類;
**2.const關(guān)鍵字**
? ? 修飾全局變量:C/C++略有不同挽懦,在上文已經(jīng)提到翰意,即C++的const修
? ? 飾的全局變量可以作為屬組的初始化的大小,而C不可以信柿;同時(shí)變量的
? ? 值不能被修改冀偶;C++利用const的這一屬性,代替C中的define進(jìn)行
? ? 全局常量的定義渔嚷;擴(kuò)展_4會(huì)就 define进鸠,const,inline進(jìn)行對(duì)比
? ? 和分析形病;
? ? 修飾局部變量:代表局部變量的值不能被修改客年;
? ? 修飾指針:這個(gè)是經(jīng)常問道的霞幅,我舉的例子可能不全面,但是是比較
? ? 常見的例子:
? ? cons t int *p;? //修飾的是p所指向的內(nèi)容不能被改變量瓜,p可
? ? 以司恳;
? ? int const *p;? //和上面是一樣的;
? ? int* const p;? //修飾的p指針不能改變绍傲;
? ? 修飾類的成員變量:必須在初始化列表初始化扔傅,除此之外,必須在初
? ? 始化列表初始化的還有烫饼,引用類型的數(shù)據(jù)成員猎塞,沒有默認(rèn)構(gòu)造函數(shù)的
? ? 對(duì)象成員,如果存在繼承關(guān)系杠纵,如果父類沒有默認(rèn)的構(gòu)造函數(shù)荠耽,則也
? ? 必須在初始化列表中被初始化,初始化列表對(duì)數(shù)據(jù)成員的初始化順序
? ? 是按照數(shù)據(jù)成員的聲明順序嚴(yán)格執(zhí)行的淡诗;
? ? 修飾類的成員函數(shù):一般放在成員函數(shù)的最后面骇塘,修飾的是類的成員
? ? 函數(shù)中的隱藏參數(shù)this指針,代表不可以通過this指針修改類的數(shù)據(jù)
? ? 成員韩容,聲明形式例如:
? ? Base::void fun() const;
? ? 關(guān)于const還有一個(gè)問題就是傳參和賦值的問題款违,一般來說,const
? ? 修飾的變量是安全的群凶,沒有const修飾的變量是不安全的插爹,一般在傳
? ? 參的時(shí)候,非const修飾的的變量可以傳給const修飾的请梢,而const
? ? 修飾的不可以傳給非const修飾的形參赠尾,這就相當(dāng)于把安全的東西交
? ? 給了不安全的人;而賦值的話更不用說了毅弧,const修飾的不可以傳給
? ? 沒有const修飾的變量气嫁;
**3.volatile**
? ? volatile一般修飾變量,而它存在的原因是因?yàn)楣蛔覀兊某绦蛟谶M(jìn)行
? ? 編譯的時(shí)候寸宵,編譯器會(huì)進(jìn)行一系列的優(yōu)化,比如元咙,某個(gè)變量被修飾為
? ? const的梯影,編譯器就認(rèn)為,這個(gè)值是只讀的庶香,就會(huì)在寄存器中保存這
? ? 個(gè)變量的值甲棍,每次需要的時(shí)候從寄存器直接讀取,但是有時(shí)候赶掖,我們
? ? 可能會(huì)在不經(jīng)意間修改了這個(gè)變量感猛,比如說我們?nèi)チ诉@個(gè)變量的地
? ? 址七扰,然后強(qiáng)行改變這個(gè)變量在內(nèi)存中的值,那么編譯器并不知道唱遭,讀
? ? 取還是從寄存器中讀取戳寸,這就造成了結(jié)果的不匹配,而volatile聲明
? ? 的變量就會(huì)告訴編譯器拷泽,這個(gè)變量隨時(shí)會(huì)改變疫鹊,需要每次都從內(nèi)從中
? ? 讀取,就是不需要優(yōu)化司致,從而避免了這個(gè)問題拆吆,其實(shí),volatile應(yīng)用
? ? 更多的場(chǎng)景是多線程對(duì)共享資源的訪問的時(shí)候脂矫,避免編譯器的優(yōu)化枣耀,
? ? 而造成多線程之間的通信不匹配!庭再;
explicit關(guān)鍵字
首先需要了解什么是隱式轉(zhuǎn)換捞奕,即在你沒有進(jìn)行顯示的強(qiáng)轉(zhuǎn)的情況
下,賦值運(yùn)算符左右兩個(gè)類型不一致的對(duì)象進(jìn)行了類型轉(zhuǎn)換拄轻;或者
函數(shù)傳參的時(shí)候進(jìn)行了類型轉(zhuǎn)換颅围; 而explicit關(guān)鍵字存在的目的就是
禁止類的構(gòu)造函數(shù)進(jìn)行隱式的類型轉(zhuǎn)換,常見的就是string類的對(duì)象
就可以隱式類型轉(zhuǎn)換恨搓,比如:
? ? strig? s = "hello world";
? ? 因?yàn)閟tring 有一個(gè)單參的char*構(gòu)造函數(shù)院促,所有可以用hello w
? ? orld構(gòu)造一個(gè)string對(duì)象,然后調(diào)用string 類的拷貝構(gòu)造函數(shù)斧抱;
? ? 有時(shí)候我們并不希望這種不是我們預(yù)期的情況發(fā)生常拓,所以,我們可以
? ? 在類的構(gòu)造函數(shù)之前+explicit關(guān)鍵字辉浦。禁止隱式轉(zhuǎn)換弄抬;
? ? ---希望讀者提建議繼續(xù)補(bǔ)充!(補(bǔ)充文章中講到的所有內(nèi)容的不足之處)
擴(kuò)展_4 define /const/inline 對(duì)比和分析
define作用于程序的預(yù)處理階段宪郊,而預(yù)處理階段做的主要工作為下面幾個(gè)
方面:宏替換眉睹,去注釋以及條件編譯; define起作用的地方就在宏替換階
段废膘,只是單純的將宏替換為代碼,例如:
#define Add(a+b) a+b
下面這段代碼用到了這個(gè)宏:
int main()
? ? {
? ? ? ? int a = 1;? //如果char a = '1';?
? ? ? ? int b = 2;
? ? ? ? cout<<Add(a+b);
? ? /*? 替換為cout<<1+2;? */
? ? ? ? return 0;
? ? }
從上面這個(gè)例子我們可以看出define的缺點(diǎn)很明顯慕蔚,首先丐黄,define只 是單純的代碼替換,不會(huì)進(jìn)行類型的檢查孔飒,再者灌闺,我們上面的宏定義 也很粗糙艰争,嚴(yán)格點(diǎn)應(yīng)該定義為: #define Add(a,b) (a)+(b) C++中一般建議使用const,枚舉定義常量桂对,這樣就會(huì)有類型檢查甩卓; 而宏定義也可以定義出和函數(shù)一樣的功能: #define Swap(type,a,b) {type tmp, tmp = a; a = b; b = tmp;} 其實(shí)就算這樣寫蕉斜,也還是存在上面提到的問題逾柿,并且這樣還不能進(jìn)行調(diào) 試,因?yàn)楹暝陬A(yù)處理階段就替換了宅此;
于是C++中又提供了一個(gè)inline內(nèi)聯(lián)關(guān)鍵字 机错,可以實(shí)現(xiàn)和define相同的
功能,并且支持類型檢查和調(diào)試父腕,一般聲明在函數(shù)的定義的前面弱匪,不過, inline只是對(duì)編譯器的一種建議璧亮,一般如果代碼在3-5行左右萧诫,且沒有復(fù) 雜的邏輯結(jié)構(gòu),例如循環(huán)啊枝嘶,遞歸啊帘饶,就可以聲明為inline,inline也
是在函數(shù)調(diào)用的地方替換代碼塊躬络,所以代碼太長(zhǎng)的話尖奔,容易造成程序膨脹,那么inline為什么可以支持調(diào)試呢穷当?
其實(shí)支持調(diào)試也只是在dbug模式下提茁,inline真正起作用是在release模
式,正好和assert相反馁菜;
提到inline,就不得不提friend友元茴扁;被一個(gè)類中聲明為友元的非本類函數(shù)和類,可以訪問本類的私有成員汪疮,這個(gè)關(guān)鍵字的存在感覺有些破壞類的封
裝性峭火,而且,友元屬性不能被傳遞和繼承智嚷;(但是實(shí)際中在有些編譯器下友元函數(shù)被子類繼承了卖丸,我也很納悶,讀者可以自己驗(yàn)證一下盏道,留言I越)C/C++學(xué)習(xí)交流QQ群728483370,大家一起加油!