C++面試知識(shí)點(diǎn)總結(jié)

技術(shù)交流QQ群:1027579432十兢,歡迎你的加入!

一.static關(guān)鍵字的作用

1.靜態(tài)成員的特點(diǎn)

  • 1.static數(shù)據(jù)成員在類的內(nèi)部聲明虐秋,但只能在類的外部定義趋观,在類的外部不能指定static,在類的定義時(shí)候進(jìn)行初始化;
  • 2.static數(shù)據(jù)成員只能在類的外部進(jìn)行初始化(特例:當(dāng)整型const static數(shù)據(jù)成員被常量表達(dá)式初始化時(shí)懂牧,就可以在類的內(nèi)部進(jìn)行初始化侈净,但還需要在外部進(jìn)行定義)。
  • 3.static數(shù)據(jù)成員可以是該成員所屬的類類型僧凤,而非static數(shù)據(jù)成員只能自身類的引用或者指針畜侦。
  • 4.static數(shù)據(jù)成員可以用作類成員函數(shù)的默認(rèn)實(shí)參。
  • 5.static數(shù)據(jù)成員的值可以改變躯保。

2.靜態(tài)成員和非靜態(tài)成員的區(qū)別

  • 1.靜態(tài)變量使用static修飾符進(jìn)行聲明旋膳,在類被實(shí)例化時(shí)創(chuàng)建,通過(guò)類和對(duì)象都可以進(jìn)行訪問(wèn)途事;
  • 2.不帶有static修飾符聲明的變量稱做非靜態(tài)變量验懊,在對(duì)象被實(shí)例化時(shí)創(chuàng)建,通過(guò)對(duì)象訪問(wèn)尸变;
    1. 一個(gè)類的所有實(shí)例的同一靜態(tài)變量都是同一個(gè)值义图,同一個(gè)類的不同實(shí)例的同一非靜態(tài)變量可以是不同的值。
  • 4.靜態(tài)函數(shù)的實(shí)現(xiàn)里不能使用非靜態(tài)成員召烂,如非靜態(tài)變量碱工、非靜態(tài)函數(shù)等。

3.靜態(tài)成員函數(shù)的特點(diǎn)

  • 1.static成員函數(shù)沒(méi)有this形參奏夫,它可以訪問(wèn)所屬類的static 成員怕篷,但不能訪問(wèn)非static成員。
  • 2.static成員函數(shù)既可以在類的內(nèi)部定義桶蛔,也可以在類的外部定義匙头,在外部定義時(shí),不能重復(fù)指定static保留字仔雷。

二.C++和C的區(qū)別

  • 設(shè)計(jì)思想上:
    • C++是面向?qū)ο蟮恼Z(yǔ)言,而C是面向過(guò)程的結(jié)構(gòu)化編程語(yǔ)言
  • 語(yǔ)法上:
    • 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
    • 1.const_cast:對(duì)于未定義const版本的成員函數(shù)蝙叛,我們通常需要使用const_cast來(lái)去除const引用對(duì)象的const,完成函數(shù)調(diào)用公给。另外一種使用方式借帘,結(jié)合static_cast,可以在非const版本的成員函數(shù)內(nèi)添加const淌铐,調(diào)用完const版本的成員函數(shù)后肺然,再使用const_cast去除const限定。
    • 2.static_cast:完成基礎(chǔ)數(shù)據(jù)類型腿准;同一個(gè)繼承體系中類型的轉(zhuǎn)換际起;任意類型與空指針類型void* 之間的轉(zhuǎn)換。
    • 3.dynamic_cast:用于動(dòng)態(tài)類型轉(zhuǎn)換吐葱。只能用于含有虛函數(shù)的類街望,用于類層次間的向上(指的是子類向基類的轉(zhuǎn)換)和向下轉(zhuǎn)化(指的是基類向子類的轉(zhuǎn)換)。只能轉(zhuǎn)指針或引用弟跑。向下轉(zhuǎn)化時(shí)灾前,如果是非法的對(duì)于指針?lè)祷豊ULL,對(duì)于引用拋異常孟辑。它通過(guò)判斷在執(zhí)行到該語(yǔ)句的時(shí)候變量的運(yùn)行時(shí)類型和要轉(zhuǎn)換的類型是否相同來(lái)判斷是否能夠進(jìn)行向下轉(zhuǎn)換哎甲。
    • 4.reinterpret_cast:幾乎什么都可以轉(zhuǎn),比如將int轉(zhuǎn)指針扑浸,可能會(huì)出問(wèn)題烧给,盡量少用;

四.C/C++ 中指針和引用的區(qū)別喝噪?

  • 1.指針有自己的一塊空間础嫡,而引用只是一個(gè)別名;
  • 2.使用sizeof看一個(gè)指針的大小是4酝惧,而引用則是被引用對(duì)象的大辛穸Α;
  • 3.指針可以被初始化為NULL晚唇,而引用必須被初始化且必須是一個(gè)已有對(duì)象 的引用巫财;
  • 4.作為參數(shù)傳遞時(shí),指針需要被解引用才可以對(duì)對(duì)象進(jìn)行操作哩陕,而直接對(duì)引 用的修改都會(huì)改變引用所指向的對(duì)象平项;
  • 5.可以有const指針赫舒,但是沒(méi)有const引用;
  • 6.指針在使用中可以指向其它對(duì)象闽瓢,但是引用只能是一個(gè)對(duì)象的引用接癌,不能 被改變;
  • 7.指針可以有多級(jí)指針(**p)扣讼,而引用只有一級(jí)
  • 8.指針和引用使用++運(yùn)算符的意義不一樣缺猛;
  • 9.如果返回動(dòng)態(tài)內(nèi)存分配的對(duì)象或者內(nèi)存,必須使用指針椭符,引用可能引起內(nèi)存泄露

五.c++中的四個(gè)智能指針: shared_ptr,unique_ptr,weak_ptr,auto_ptr

  • 智能指針出現(xiàn)的原因:智能指針的作用是管理一個(gè)指針荔燎,因?yàn)榇嬖谝韵逻@種情況:申請(qǐng)的空間在函數(shù)結(jié)束時(shí)忘記釋放,造成內(nèi)存泄漏销钝。使用智能指針可以很大程度上的避免這個(gè)問(wèn)題有咨,因?yàn)橹悄苤羔樉褪且粋€(gè)類,當(dāng)超出了類的作用域是曙搬,類會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)摔吏,析構(gòu)函數(shù)會(huì)自動(dòng)釋放資源。所以智能指針的作用原理就是在函數(shù)結(jié)束時(shí)自動(dòng)釋放內(nèi)存空間纵装,不需要手動(dòng)釋放內(nèi)存空間征讲。
    • 1.auto_ptr(c++98的方案,c++11已經(jīng)拋棄)原因是缺乏語(yǔ)言特性如 “針對(duì)構(gòu)造和賦值” 的 std::move 語(yǔ)義橡娄,以及其他瑕疵诗箍。
    • 2.unique_ptr(替換auto_ptr):是 C++11 才開始提供的類型,是一種在異常時(shí)可以幫助避免資源泄漏的智能指針挽唉。采用獨(dú)占式擁有滤祖,意味著可以確保一個(gè)對(duì)象和其相應(yīng)的資源同一時(shí)間只被一個(gè) pointer 擁有。一旦擁有著被銷毀或變成 empty瓶籽,或開始擁有另一個(gè)對(duì)象匠童,先前擁有的那個(gè)對(duì)象就會(huì)被銷毀,其任何相應(yīng)資源亦會(huì)被釋放塑顺。實(shí)現(xiàn)獨(dú)占式擁有(exclusive ownership)或嚴(yán)格擁有(strict ownership)概念汤求,保證同一時(shí)間內(nèi)只有一個(gè)智能指針可以指向該對(duì)象。你可以移交擁有權(quán)严拒。它對(duì)于避免內(nèi)存泄漏(resource leak)——如 new 后忘記 delete ——特別有用扬绪。unique_ptr 用于取代 auto_ptr
    • 3.shared_ptr:shared_ptr實(shí)現(xiàn)共享式擁有概念。多個(gè)智能指針指向相同對(duì)象裤唠,該對(duì)象和其相關(guān)資源會(huì)在 “最后一個(gè) reference 被銷毀” 時(shí)被釋放挤牛。為了在結(jié)構(gòu)較復(fù)雜的情景中執(zhí)行上述工作,標(biāo)準(zhǔn)庫(kù)提供 weak_ptr种蘸、bad_weak_ptr 和 enable_shared_from_this 等輔助類墓赴。多個(gè)智能指針可以共享同一個(gè)對(duì)象竞膳,對(duì)象的最末一個(gè)擁有著有責(zé)任銷毀對(duì)象,并清理與該對(duì)象相關(guān)的所有資源竣蹦。
    • 4.weak_ptr:weak_ptr 允許你共享但不擁有某對(duì)象顶猜,一旦最末一個(gè)擁有該對(duì)象的智能指針失去了所有權(quán)沧奴,任何 weak_ptr 都會(huì)自動(dòng)成空(empty)痘括。因此,在 default 和 copy 構(gòu)造函數(shù)之外滔吠,weak_ptr 只提供 “接受一個(gè) shared_ptr” 的構(gòu)造函數(shù)纲菌。可打破環(huán)狀引用(cycles of references疮绷,兩個(gè)其實(shí)已經(jīng)沒(méi)有被使用的對(duì)象彼此互指翰舌,使之看似還在 “被使用” 的狀態(tài))的問(wèn)題。

六.野指針

  • 野指針就是指向一個(gè)已刪除的對(duì)象或者未申請(qǐng)?jiān)L問(wèn)受限內(nèi)存區(qū)域的指針

七.為什么析構(gòu)函數(shù)必須是虛函數(shù)冬骚?為什么C++默認(rèn)的析構(gòu)函數(shù)不是虛函數(shù)

  • 將可能會(huì)被繼承的父類的析構(gòu)函數(shù)設(shè)置為虛函數(shù)椅贱,可以保證當(dāng)我們new一個(gè)子類,然后使用基類指針指向該子類對(duì)象只冻,釋放基類指針時(shí)可以釋放掉子類的空間庇麦,防止內(nèi)存泄漏。
  • C++默認(rèn)的析構(gòu)函數(shù)不是虛函數(shù)是因?yàn)樘摵瘮?shù)需要額外的虛函數(shù)表和虛表指針喜德,占用額外的內(nèi)存山橄。而對(duì)于不會(huì)被繼承的類來(lái)說(shuō),其析構(gòu)函數(shù)如果是虛函數(shù)舍悯,就會(huì)浪費(fèi)內(nèi)存航棱。因此C++默認(rèn)的析構(gòu)函數(shù)不是虛函數(shù),而是只有當(dāng)需要當(dāng)作父類時(shí)萌衬,設(shè)置為虛函數(shù)饮醇。

八.函數(shù)指針

  • 1.定義:函數(shù)指針是指向函數(shù)的指針變量。函數(shù)指針本身首先是一個(gè)指針變量秕豫,該指針變量指向一個(gè)具體的函數(shù)朴艰。這正如用指針變量可指向整型變量、字符型馁蒂、數(shù)組一樣呵晚,這里是指向函數(shù)。C在編譯時(shí)沫屡,每一個(gè)函數(shù)都有一個(gè)入口地址饵隙,該入口地址就是函數(shù)指針?biāo)赶虻牡刂贰S辛酥赶蚝瘮?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);                        // 通過(guò)函數(shù)指針pf調(diào)用函數(shù)fun
    

九.fork函數(shù)的作用

  • Fork:創(chuàng)建一個(gè)和當(dāng)前進(jìn)程映像一樣的進(jìn)程可以通過(guò)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ù)運(yùn)行。在子進(jìn)程中故俐,成功的fork( )調(diào)用會(huì)返回0想鹰。在父進(jìn)程中fork( )返回子進(jìn)程的pid。如果出現(xiàn)錯(cuò)誤药版,fork( )返回一個(gè)負(fù)值辑舷。
  • 最常見(jiàn)的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í)行”的方式是很常見(jiàn)的。

十.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ù)名也應(yīng)與類名相同波材,只是在函數(shù)名前面加一個(gè)位取反符~,例如~stud( )身隐,以區(qū)別于構(gòu)造函數(shù)廷区。它不能帶任何參數(shù),也沒(méi)有返回值(包括void類型)贾铝。只能有一個(gè)析構(gòu)函數(shù)隙轻,不能重載
  • 如果用戶沒(méi)有編寫析構(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)單的類中沒(méi)有用顯式的析構(gòu)函數(shù)锋勺。
  • 如果一個(gè)類中有指針,且在使用的過(guò)程中動(dòng)態(tài)的申請(qǐng)了內(nèi)存,那么最好顯式構(gòu)造析構(gòu)函數(shù)在銷毀類之前佳吞,釋放掉申請(qǐng)的內(nèi)存空間,避免內(nèi)存泄漏贪惹。
  • 類析構(gòu)順序:1)派生類本身的析構(gòu)函數(shù);2)對(duì)象成員析構(gòu)函數(shù)寂嘉;3)基類析構(gòu)函數(shù)奏瞬。

十一.靜態(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)存開銷。

十二.重載和重寫

  • 重載:兩個(gè)函數(shù)名相同棵譬,但是參數(shù)列表不同(個(gè)數(shù),類型)预伺,返回值類型沒(méi)有要求订咸,在同一作用域中
  • 重寫:子類繼承了父類,父類中的函數(shù)是虛函數(shù)酬诀,在子類中重新定義了這個(gè)虛函數(shù)脏嚷,這種情況是重寫

十三.虛函數(shù)和多態(tài)

  • 多態(tài)的實(shí)現(xiàn)主要分為靜態(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è)父類類型的指針指向一個(gè)子類對(duì)象時(shí)候趾唱,使用父類的指針去調(diào)用子類中重寫了的父類中的虛函數(shù)的時(shí)候,會(huì)調(diào)用子類重寫過(guò)后的函數(shù)蜻懦,在父類中聲明為加了virtual關(guān)鍵字的函數(shù)甜癞,在子類中重寫時(shí)候不需要加virtual也是虛函數(shù)。
  • 虛函數(shù)的實(shí)現(xiàn):在有虛函數(shù)的類中宛乃,類的最開始部分是一個(gè)虛函數(shù)表的指針悠咱,這個(gè)指針指向一個(gè)虛函數(shù)表,表中放了虛函數(shù)的地址征炼,實(shí)際的虛函數(shù)在代碼段(.text)中析既。當(dāng)子類繼承了父類的時(shí)候也會(huì)繼承其虛函數(shù)表,當(dāng)子類重寫父類中虛函數(shù)時(shí)候谆奥,會(huì)將其繼承到的虛函數(shù)表中的地址替換為重新寫的函數(shù)地址眼坏。使用了虛函數(shù),會(huì)增加訪問(wèn)內(nèi)存開銷雄右,降低效率空骚。

十四.下面四個(gè)代碼的區(qū)別const char * arr = "123"; char * brr = "123"; const char crr[] = "123"; char drr[] = "123";

  • const char * arr = "123"; // 字符串123保存在常量區(qū)纺讲,const本來(lái)是修飾arr指向的值不能通過(guò)arr去修改,但是字符串“123”在常量區(qū)囤屹,本來(lái)就不能改變熬甚,所以加不加const效果都一樣
  • char * brr = "123"; // 字符串123保存在常量區(qū),這個(gè)brr指針指向的是同一個(gè)位置肋坚,同樣不能通過(guò)brr去修改"123"的值
  • const char crr[] = "123"; // 這里123本來(lái)是在棧上的乡括,但是編譯器可能會(huì)做某些優(yōu)化,將其放到常量區(qū)
  • char drr[] = "123"; // 字符串123保存在棧區(qū)智厌,可以通過(guò)drr去修改

十五.const修飾成員函數(shù)的目的是什么诲泌?

  • const修飾的成員函數(shù)表明函數(shù)調(diào)用不會(huì)對(duì)對(duì)象做出任何更改,事實(shí)上铣鹏,如果確認(rèn)不會(huì)對(duì)對(duì)象做更改敷扫,就應(yīng)該為函數(shù)加上const限定,這樣無(wú)論const對(duì)象還是普通對(duì)象都可以調(diào)用該函數(shù)诚卸。

十六.C++里是怎么定義常量的葵第?常量存放在內(nèi)存的哪個(gè)位置?

  • 對(duì)于局部常量合溺,存放在棧區(qū)卒密;對(duì)于全局常量,編譯期一般不分配內(nèi)存棠赛,放在符號(hào)表中以提高訪問(wèn)效率哮奇;字面值常量,比如字符串睛约,放在常量區(qū)鼎俘。

十七.new/delete與malloc/free的區(qū)別是什么

  • 首先,new/delete是C++的關(guān)鍵字痰腮,而malloc/free是C語(yǔ)言的庫(kù)函數(shù)而芥;后者使用必須指明申請(qǐng)內(nèi)存空間的大小,對(duì)于類類型的對(duì)象膀值,后者不會(huì)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)棍丐。

十八.虛函數(shù)表具體是怎樣實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)的?

  • 子類若重寫父類虛函數(shù),虛函數(shù)表中沧踏,該函數(shù)的地址會(huì)被替換歌逢,對(duì)于存在虛函數(shù)的類的對(duì)象,在VS中翘狱,對(duì)象模型的頭部存放指向虛函數(shù)表的指針秘案,通過(guò)該機(jī)制實(shí)現(xiàn)多態(tài)。

十九.C語(yǔ)言是怎么進(jìn)行函數(shù)調(diào)用的?

  • 每一個(gè)函數(shù)調(diào)用都會(huì)分配函數(shù)棧阱高,在棧內(nèi)進(jìn)行函數(shù)執(zhí)行過(guò)程赚导。調(diào)用前,先把返回地址壓棧赤惊,然后把當(dāng)前函數(shù)的esp指針壓棧吼旧。

二十.C++如何處理返回值?

  • 生成一個(gè)臨時(shí)變量未舟,把它的引用作為函數(shù)參數(shù)傳入函數(shù)內(nèi)圈暗。

二十一.C++中拷貝賦值函數(shù)的形參能否進(jìn)行值傳遞?

  • 不能裕膀。如果是這種情況下员串,調(diào)用拷貝構(gòu)造函數(shù)的時(shí)候,首先要將實(shí)參傳遞給形參昼扛,這個(gè)傳遞的時(shí)候又要調(diào)用拷貝構(gòu)造函數(shù)寸齐。。如此循環(huán)野揪,無(wú)法完成拷貝访忿,棧也會(huì)滿。

二十二.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)。

二十三.fork,wait,exec函數(shù)的作用

  • 父進(jìn)程產(chǎn)生子進(jìn)程使用fork拷貝出來(lái)一個(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ì)發(fā)生阻塞,直到有子進(jìn)程狀態(tài)改變,執(zhí)行成功返回0蛋铆,錯(cuò)誤返回-1馋评。exec執(zhí)行成功則子進(jìn)程從新的程序開始運(yùn)行,無(wú)返回值刺啦,執(zhí)行失敗返回-1留特。

二十四.C++中類成員的訪問(wèn)權(quán)限

  • C++通過(guò) public、protected、private 三個(gè)關(guān)鍵字來(lái)控制成員變量和成員函數(shù)的訪問(wèn)權(quán)限蜕青,它們分別表示公有的苟蹈、受保護(hù)的、私有的右核,被稱為成員訪問(wèn)限定符慧脱。在類的內(nèi)部(定義類的代碼內(nèi)部),無(wú)論成員被聲明為 public蒙兰、protected 還是 private磷瘤,都是可以互相訪問(wèn)的,沒(méi)有訪問(wèn)權(quán)限的限制搜变。在類的外部(定義類的代碼之外)采缚,只能通過(guò)對(duì)象訪問(wèn)成員,并且通過(guò)對(duì)象只能訪問(wèn) public 屬性的成員挠他,不能訪問(wèn) private扳抽、protected 屬性的成員。

二十五. C++中struct和class的區(qū)別

  • 總的來(lái)說(shuō)殖侵,struct 更適合看成是一個(gè)數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)體贸呢,class 更適合看成是一個(gè)對(duì)象的實(shí)現(xiàn)體。
  • 區(qū)別:最本質(zhì)的一個(gè)區(qū)別就是默認(rèn)的訪問(wèn)控制
    • 默認(rèn)的繼承訪問(wèn)權(quán)限拢军。struct 是 public 的楞陷,class 是 private 的
    • struct 作為數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)體,它默認(rèn)的數(shù)據(jù)訪問(wèn)控制是 public 的茉唉,而 class 作為對(duì)象的實(shí)現(xiàn)體固蛾,它默認(rèn)的成員變量訪問(wèn)控制是 private 的。

二十六.C++類的內(nèi)部可以定義引用數(shù)據(jù)成員嗎度陆?

  • 可以艾凯,必須通過(guò)成員函數(shù)初始化列表初始化
    class MyClass
    {
    public:
        MyClass(int &i):  a(1),   b(i){         //  構(gòu)造函數(shù)初始化列表中是初始化工作
            //   在這里做的是賦值而非初始化工作
        }
    private:
        const int a;
        int &b;  // 引用數(shù)據(jù)成員b,必須通過(guò)列表初始化!
    };
    

二十七.什么是右值引用懂傀,跟左值又有什么區(qū)別趾诗?

  • 左值:能對(duì)表達(dá)式取地址、或具名對(duì)象/變量蹬蚁。一般指表達(dá)式結(jié)束后依然存在的持久對(duì)象恃泪。
  • 右值:不能對(duì)表達(dá)式取地址,或匿名對(duì)象缚忧。一般指表達(dá)式結(jié)束就不再存在的臨時(shí)對(duì)象悟泵。
  • 右值引用和左值引用的區(qū)別:
    • 1.左值可以尋址,而右值不可以闪水;
    • 2.左值可以被賦值糕非,右值不可以被賦值蒙具,可以用來(lái)給左值賦值;
    • 3.左值可變,右值不可變(僅對(duì)基礎(chǔ)類型適用朽肥,用戶自定義類型右值引用可以通過(guò)成員函數(shù)改變)禁筏。

二十八.C++源文件從文本到可執(zhí)行文件經(jīng)歷的過(guò)程?

  • 對(duì)于C++源文件衡招,從文本到可執(zhí)行文件一般需要四個(gè)過(guò)程:
    • 預(yù)處理階段:對(duì)源代碼文件中文件包含關(guān)系(頭文件)篱昔、預(yù)編譯語(yǔ)句(宏定義)進(jìn)行分析和替換,生成預(yù)編譯文件始腾。
    • 編譯階段:將經(jīng)過(guò)預(yù)處理后的預(yù)編譯文件轉(zhuǎn)換成特定匯編代碼州刽,生成匯編文件
    • 匯編階段:將編譯階段生成的匯編文件轉(zhuǎn)化成機(jī)器碼,生成可重定位目標(biāo)文件
    • 鏈接階段:將多個(gè)目標(biāo)文件及所需要的庫(kù)連接成最終的可執(zhí)行目標(biāo)文件

二十九.include頭文件的順序以及雙引號(hào)””和尖括號(hào)<>的區(qū)別浪箭?

  • include頭文件的順序:對(duì)于include的頭文件來(lái)說(shuō)穗椅,如果在文件a.h中聲明一個(gè)在文件b.h中定義的變量,而不引用b.h奶栖。那么要在a.c文件中引用b.h文件匹表,并且要先引用b.h,后引用a.h,否則匯報(bào)變量類型未聲明錯(cuò)誤宣鄙。
  • 雙引號(hào)和尖括號(hào)的區(qū)別:編譯器預(yù)處理階段查找頭文件的路徑不一樣袍镀。對(duì)于使用雙引號(hào)包含的頭文件,查找頭文件路徑的順序?yàn)椋寒?dāng)前頭文件目錄冻晤、編譯器設(shè)置的頭文件路徑(編譯器可使用-I顯式指定搜索路徑)苇羡、系統(tǒng)變量CPLUS_INCLUDE_PATH/C_INCLUDE_PATH指定的頭文件路徑;對(duì)于使用尖括號(hào)包含的頭文件鼻弧,查找頭文件的路徑順序?yàn)椋壕幾g器設(shè)置的頭文件路徑(編譯器可使用-I顯式指定搜索路徑)宣虾、系統(tǒng)變量CPLUS_INCLUDE_PATH/C_INCLUDE_PATH指定的頭文件路徑。

三十.什么時(shí)候會(huì)發(fā)生段錯(cuò)誤温数?

  • 段錯(cuò)誤通常發(fā)生在訪問(wèn)非法內(nèi)存地址的時(shí)候,具體來(lái)說(shuō)分為以下幾種情況:
    • 使用野指針
    • 試圖修改字符串常量的內(nèi)容

三十一.C++11有哪些新特性蜻势?

  • auto關(guān)鍵字:編譯器可以根據(jù)初始值自動(dòng)推導(dǎo)出類型撑刺,但是不能用于函數(shù)傳參以及數(shù)組類型的推導(dǎo);
  • nullptr關(guān)鍵字:nullptr是一種特殊類型的字面值握玛,它可以被轉(zhuǎn)換成任意其它的指針類型够傍;而NULL一般被宏定義為0,在遇到重載時(shí)可能會(huì)出現(xiàn)問(wèn)題挠铲。
  • 智能指針:C++11新增了std::shared_ptr冕屯、std::weak_ptr等類型的智能指針,用于解決內(nèi)存管理的問(wèn)題拂苹。
  • 初始化列表:使用初始化列表來(lái)對(duì)類進(jìn)行初始化
  • 右值引用:基于右值引用可以實(shí)現(xiàn)移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā)安聘,消除兩個(gè)對(duì)象交互時(shí)不必要的對(duì)象拷貝,節(jié)省運(yùn)算存儲(chǔ)資源,提高效率
  • atomic原子操作用于多線程資源互斥操作
  • 新增STL容器array以及tuple

三十二.const的作用

  • 1.修飾變量浴韭,說(shuō)明該變量不可以被修改
  • 2.修飾指針丘喻,分為指向常量的指針(即常量指針)和指針常量
  • 3.常量引用,經(jīng)常用于形參類型念颈,既避免了拷貝泉粉,又避免了函數(shù)對(duì)值的修改
  • 4.修飾成員函數(shù),說(shuō)明該成員函數(shù)內(nèi)不能修改成員變量
  • const用法如下:
// 類
class A
{
private:
    const int a;                // 常對(duì)象成員榴芳,只能在初始化列表賦值

public:
    // 構(gòu)造函數(shù)
    A() : a(0) { };
    A(int x) : a(x) { };        // 初始化列表

    // const可用于對(duì)重載函數(shù)的區(qū)分
    int getValue();             // 普通成員函數(shù)
    int getValue() const;       // 常成員函數(shù)嗡靡,不得修改類中的任何數(shù)據(jù)成員的值
};

void function()
{
    // 對(duì)象
    A b;                        // 普通對(duì)象,可以調(diào)用全部成員函數(shù)窟感、更新常成員變量
    const A a;                  // 常對(duì)象讨彼,只能調(diào)用常成員函數(shù)
    const A *p = &a;            // 常指針
    const A &q = a;             // 常引用

    // 指針
    char greeting[] = "Hello";
    char* p1 = greeting;                // 指針變量,指向字符數(shù)組變量
    const char* p2 = greeting;          // 常量指針即常指針肌括,指針的指向可以改變点骑,但是所存的內(nèi)容不能變
    char const* p2 = greeting;     // 與const char* p2 等價(jià)
    char* const p3 = greeting;          // 指針常量,指針是一個(gè)常量谍夭,即指針的指向不能改變黑滴,但是指針?biāo)娴膬?nèi)容可以改變
    const char* const p4 = greeting;    // 指向常量的常指針,指針和指針?biāo)娴膬?nèi)容都不能改變紧索,本質(zhì)是一個(gè)常量
}

// 函數(shù)
void function1(const int Var);           // 傳遞過(guò)來(lái)的參數(shù)在函數(shù)內(nèi)不可變
void function2(const char* Var);         // 參數(shù)為常量指針即指針?biāo)傅膬?nèi)容為常量不能變袁辈,指針指向可以改變
void function3(char* const Var);         // 參數(shù)為指針常量
void function4(const int& Var);          // 引用參數(shù)在函數(shù)內(nèi)為常量

// 函數(shù)返回值
const int function5();      // 返回一個(gè)常數(shù)
const int* function6();     // 返回一個(gè)指向常量的指針變量即常量指針,使用:const int *p = function6();
int* const function7();     // 返回一個(gè)指向變量的常指針即指針常量珠漂,使用:int* const p = function7();

三十三.this 指針

  • this 指針是一個(gè)隱含于每一個(gè)非靜態(tài)成員函數(shù)中的特殊指針晚缩。它指向調(diào)用該成員函數(shù)的那個(gè)對(duì)象。
  • 當(dāng)對(duì)一個(gè)對(duì)象調(diào)用成員函數(shù)時(shí)媳危,編譯程序先將對(duì)象的地址賦給 this 指針荞彼,然后調(diào)用成員函數(shù),每次成員函數(shù)存取數(shù)據(jù)成員時(shí)待笑,都隱式使用 this 指針鸣皂。
  • 當(dāng)一個(gè)成員函數(shù)被調(diào)用時(shí),自動(dòng)向它傳遞一個(gè)隱含的參數(shù)暮蹂,該參數(shù)是一個(gè)指向這個(gè)成員函數(shù)所在的對(duì)象的指針寞缝。
  • this 指針被隱含地聲明為: ClassName *const this,這意味著不能給 this 指針賦值仰泻;在 ClassName 類的 const 成員函數(shù)中荆陆,this 指針的類型為:const ClassName* const,這說(shuō)明不能對(duì) this 指針?biāo)赶虻倪@種對(duì)象是不可修改的(即不能對(duì)這種對(duì)象的數(shù)據(jù)成員進(jìn)行賦值操作)集侯;
  • this 并不是一個(gè)常規(guī)變量被啼,而是個(gè)右值帜消,所以不能取得 this 的地址(不能 &this)。
    在以下場(chǎng)景中趟据,經(jīng)常需要顯式引用 this 指針:
    • 為實(shí)現(xiàn)對(duì)象的鏈?zhǔn)揭茫?/li>
    • 為避免對(duì)同一對(duì)象進(jìn)行賦值操作券犁;
    • 在實(shí)現(xiàn)一些數(shù)據(jù)結(jié)構(gòu)時(shí),如 list汹碱。

三十四.inline內(nèi)聯(lián)函數(shù)

  • 內(nèi)聯(lián)函數(shù)的特點(diǎn):
    • 相當(dāng)于把內(nèi)聯(lián)函數(shù)里面的內(nèi)容寫在調(diào)用內(nèi)聯(lián)函數(shù)處粘衬;
    • 相當(dāng)于不用執(zhí)行進(jìn)入函數(shù)的步驟,直接執(zhí)行函數(shù)體咳促;
    • 相當(dāng)于宏稚新,卻比宏多了類型檢查,真正具有函數(shù)特性跪腹;
    • 編譯器一般不內(nèi)聯(lián)包含循環(huán)褂删、遞歸、switch 等復(fù)雜操作的內(nèi)聯(lián)函數(shù)冲茸;
    • 在類聲明中定義的函數(shù)屯阀,除了虛函數(shù)的其他函數(shù)都會(huì)自動(dòng)隱式地當(dāng)成內(nèi)聯(lián)函數(shù)。
  • 內(nèi)聯(lián)函數(shù)的使用:
// 聲明1(加 inline轴术,建議使用)
inline int functionName(int first, int second,...);

// 聲明2(不加 inline)
int functionName(int first, int second,...);

// 定義
inline int functionName(int first, int second,...) {/****/};

// 類內(nèi)定義难衰,隱式內(nèi)聯(lián)
class A {
    int doA() { return 0; }         // 隱式內(nèi)聯(lián)
}

// 類外定義,需要顯式內(nèi)聯(lián)
class A {
    int doA();
}
inline int A::doA() { return 0; }   // 需要顯式內(nèi)聯(lián)
  • 編譯器對(duì)內(nèi)聯(lián)函數(shù)的處理步驟:
    • 將 inline 函數(shù)體復(fù)制到 inline 函數(shù)調(diào)用點(diǎn)處逗栽;
    • 為所用 inline 函數(shù)中的局部變量分配內(nèi)存空間盖袭;
    • 將 inline 函數(shù)的的輸入?yún)?shù)和返回值映射到調(diào)用方法的局部變量空間中;
    • 如果 inline 函數(shù)有多個(gè)返回點(diǎn)彼宠,將其轉(zhuǎn)變?yōu)?inline 函數(shù)代碼塊末尾的分支(使用 GOTO)
  • 使用內(nèi)聯(lián)函數(shù)的優(yōu)缺點(diǎn):
    • 優(yōu)點(diǎn):
      • 內(nèi)聯(lián)函數(shù)同宏函數(shù)一樣將在被調(diào)用處進(jìn)行代碼展開鳄虱,省去了參數(shù)壓棧、棧幀開辟與回收凭峡,結(jié)果返回等拙已,從而提高程序運(yùn)行速度。
      • 內(nèi)聯(lián)函數(shù)相比宏函數(shù)來(lái)說(shuō)摧冀,在代碼展開時(shí)悠栓,會(huì)做安全檢查或自動(dòng)類型轉(zhuǎn)換(同普通函數(shù)),而宏定義則不會(huì)按价。
      • 在類中聲明同時(shí)定義的成員函數(shù),自動(dòng)轉(zhuǎn)化為內(nèi)聯(lián)函數(shù)笙瑟,因此內(nèi)聯(lián)函數(shù)可以訪問(wèn)類的成員變量楼镐,宏定義則不能。
      • 內(nèi)聯(lián)函數(shù)在運(yùn)行時(shí)可調(diào)試往枷,而宏定義不可以框产。
    • 缺點(diǎn):
      • 代碼膨脹凄杯。內(nèi)聯(lián)是以代碼膨脹(復(fù)制)為代價(jià),消除函數(shù)調(diào)用帶來(lái)的開銷秉宿。如果執(zhí)行函數(shù)體內(nèi)代碼的時(shí)間戒突,相比于函數(shù)調(diào)用的開銷較大,那么效率的收獲會(huì)很少描睦。另一方面膊存,每一處內(nèi)聯(lián)函數(shù)的調(diào)用都要復(fù)制代碼,將使程序的總代碼量增大忱叭,消耗更多的內(nèi)存空間隔崎。
      • inline 函數(shù)無(wú)法隨著函數(shù)庫(kù)升級(jí)而升級(jí)。inline函數(shù)的改變需要重新編譯韵丑,不像 non-inline 可以直接鏈接爵卒。
      • 是否內(nèi)聯(lián),程序員不可控撵彻。內(nèi)聯(lián)函數(shù)只是對(duì)編譯器的建議钓株,是否對(duì)函數(shù)內(nèi)聯(lián),決定權(quán)在于編譯器陌僵。
  • 虛函數(shù)可以是內(nèi)聯(lián)函數(shù)嗎轴合?
    • 虛函數(shù)可以是內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)是可以修飾虛函數(shù)的拾弃,但是當(dāng)虛函數(shù)表現(xiàn)多態(tài)性的時(shí)候不能內(nèi)聯(lián)值桩。
    • 內(nèi)聯(lián)是在編譯器建議編譯器內(nèi)聯(lián),而虛函數(shù)的多態(tài)性在運(yùn)行期豪椿,編譯器無(wú)法知道運(yùn)行期調(diào)用哪個(gè)代碼奔坟,因此虛函數(shù)表現(xiàn)為多態(tài)性時(shí)(運(yùn)行期)不可以內(nèi)聯(lián)。
    • inline virtual 唯一可以內(nèi)聯(lián)的時(shí)候是:編譯器知道所調(diào)用的對(duì)象是哪個(gè)類(如 Base::who())搭盾,這只有在編譯器具有實(shí)際對(duì)象而不是對(duì)象的指針或引用時(shí)才會(huì)發(fā)生咳秉。
    • 虛函數(shù)內(nèi)聯(lián)使用實(shí)例如下:
#include <iostream>
using namespace std;
class Base
{
public:
    inline virtual void who()
    {
        cout << "I am Base\n";
    }
    virtual ~Base() {}
};
class Derived : public Base
{
public:
    inline void who()  // 不寫inline時(shí)隱式內(nèi)聯(lián)
    {
        cout << "I am Derived\n";
    }
};

int main()
{
    // 此處的虛函數(shù) who(),是通過(guò)類(Base)的具體對(duì)象(b)來(lái)調(diào)用的鸯隅,編譯期間就能確定了澜建,所以它可以是內(nèi)聯(lián)的,但最終是否內(nèi)聯(lián)取決于編譯器蝌以。
    Base b;
    b.who();

    // 此處的虛函數(shù)是通過(guò)指針調(diào)用的炕舵,呈現(xiàn)多態(tài)性,需要在運(yùn)行時(shí)期間才能確定跟畅,所以不能為內(nèi)聯(lián)咽筋。
    Base *ptr = new Derived();
    ptr->who();

    // 因?yàn)锽ase有虛析構(gòu)函數(shù)(virtual ~Base() {}),所以 delete 時(shí)徊件,會(huì)先調(diào)用派生類(Derived)析構(gòu)函數(shù)奸攻,再調(diào)用基類(Base)析構(gòu)函數(shù)蒜危,防止內(nèi)存泄漏。
    delete ptr;
    ptr = nullptr;

    system("pause");
    return 0;
}

三十五.volatile關(guān)鍵字

volatile int i=10;
  • volatile 關(guān)鍵字是一種類型修飾符睹耐,用它聲明的類型變量表示可以被某些編譯器未知的因素(操作系統(tǒng)辐赞、硬件、其它線程等)更改硝训。所以使用 volatile 告訴編譯器不應(yīng)對(duì)這樣的對(duì)象進(jìn)行優(yōu)化响委。
  • volatile 關(guān)鍵字聲明的變量,每次訪問(wèn)時(shí)都必須從內(nèi)存中取出值(沒(méi)有被 volatile 修飾的變量捎迫,可能由于編譯器的優(yōu)化晃酒,從 CPU 寄存器中取值)
  • const 可以是 volatile (如只讀的狀態(tài)寄存器)
  • 指針可以是volatile

三十六.assert()

  • 斷言是宏,而非函數(shù)窄绒。assert 宏的原型定義在 <assert.h>(C)贝次、<cassert>(C++)中,其作用是如果它的條件返回錯(cuò)誤彰导,則終止程序執(zhí)行蛔翅。可以通過(guò)定義 NDEBUG 來(lái)關(guān)閉 assert位谋,但是需要在源代碼的開頭山析,include <assert.h> 之前。
  • assert()使用
#define NDEBUG          // 加上這行掏父,則 assert 不可用
#include <assert.h>

assert( p != NULL );    // assert 不可用

三十七.sizeof()運(yùn)算符

  • sizeof 對(duì)數(shù)組笋轨,得到整個(gè)數(shù)組所占空間大小。
  • sizeof 對(duì)指針赊淑,得到指針本身所占空間大小爵政。

三十八.#pragma pack(n)

  • 用途:設(shè)定結(jié)構(gòu)體、聯(lián)合以及類成員變量以 n 字節(jié)方式對(duì)齊
  • #pragma pack(n)使用實(shí)例:
#pragma pack(push)  // 保存對(duì)齊狀態(tài)
#pragma pack(4)     // 設(shè)定為 4 字節(jié)對(duì)齊

struct test
{
    char m1;
    double m4;
    int m3;
};

#pragma pack(pop)   // 恢復(fù)對(duì)齊狀態(tài)

三十九. extern "C"

  • 用途:extern "C" 的作用是讓 C++ 編譯器將 extern "C" 聲明的代碼當(dāng)作 C 語(yǔ)言代碼處理陶缺,可以避免 C++ 因符號(hào)修飾導(dǎo)致代碼不能和C語(yǔ)言庫(kù)中的符號(hào)進(jìn)行鏈接的問(wèn)題钾挟。
  • 被 extern 限定的函數(shù)或變量是 extern 類型的;被 extern "C" 修飾的變量和函數(shù)是按照 C 語(yǔ)言方式編譯和鏈接的
  • extern "C"實(shí)例如下:
#ifdef __cplusplus
extern "C" {
#endif

void *memset(void *, int, size_t);

#ifdef __cplusplus
}
#endif

四十.struct 和 typedef struct

  • C語(yǔ)言中:
// c
typedef struct Student {
    int age;
} S;
// 等價(jià)于下面
struct Student {
    int age;
} ;
typedef struct Student S;
  • C++中:
    • 1.如果在類標(biāo)識(shí)符空間定義了 struct Student {...};饱岸,使用 Student me; 時(shí)掺出,編譯器將搜索全局標(biāo)識(shí)符表,Student 未找到苫费,則在類標(biāo)識(shí)符內(nèi)搜索汤锨。即表現(xiàn)為可以使用 Student 也可以使用 struct Student,如下:
          // cpp
          struct Student {
              int age;
          };
      
          void f( Student me );       // 正確百框,"struct" 關(guān)鍵字可省略
      
    • 2.若定義了與 Student 同名函數(shù)之后泥畅,則 Student 只代表函數(shù),不代表結(jié)構(gòu)體,如下:
          typedef struct Student {
              int age;
          } S;
      
          void Student() {}           // 正確位仁,定義后 "Student" 只代表此函數(shù)
      
          //void S() {}               // 錯(cuò)誤,符號(hào) "S" 已經(jīng)被定義為一個(gè) "struct Student" 的別名
      
          int main() {
              Student();
              struct Student me;      // 或者 "S me";
              return 0;
          }
      

四十一.union聯(lián)合體

  • 聯(lián)合(union)是一種節(jié)省空間的特殊的類方椎,一個(gè) union 可以有多個(gè)數(shù)據(jù)成員聂抢,但是在任意時(shí)刻只有一個(gè)數(shù)據(jù)成員可以有值。當(dāng)某個(gè)成員被賦值后其他成員變?yōu)槲炊x狀態(tài)棠众。聯(lián)合有如下特點(diǎn):
    • 默認(rèn)訪問(wèn)控制符為 public
    • 可以含有構(gòu)造函數(shù)琳疏、析構(gòu)函數(shù)
    • 不能含有引用類型的成員
    • 不能繼承自其他類,不能作為基類
    • 不能含有虛函數(shù)
    • 匿名 union 在定義所在作用域可直接訪問(wèn) union 成員
    • 匿名 union 不能包含 protected 成員或 private 成員
    • 全局匿名聯(lián)合必須是靜態(tài)(static)的
  • union使用實(shí)例如下:
    #include<iostream>
    
    union UnionTest {
        UnionTest() : i(10) {};
        int i;
        double d;
    };
    
    static union {
        int i;
        double d;
    };
    
    int main() {
        UnionTest u;
    
        union {
            int i;
            double d;
        };
    
        std::cout << u.i << std::endl;  // 輸出 UnionTest 聯(lián)合的 10
    
        ::i = 20;
        std::cout << ::i << std::endl;  // 輸出全局靜態(tài)匿名聯(lián)合的 20
    
        i = 30;
        std::cout << i << std::endl;    // 輸出局部匿名聯(lián)合的 30
    
        return 0;
    }
    

四十二.explicit(顯式)關(guān)鍵字

  • explicit 修飾構(gòu)造函數(shù)時(shí)闸拿,可以防止隱式轉(zhuǎn)換和復(fù)制初始化空盼,必須顯式初始化
  • explicit 修飾轉(zhuǎn)換函數(shù)時(shí),可以防止隱式轉(zhuǎn)換新荤,但按語(yǔ)境轉(zhuǎn)換 除外
  • explicit使用實(shí)例如下:
struct A
{
    A(int) { }
    operator bool() const { return true; }
};

struct B
{
    explicit B(int) {}
    explicit operator bool() const { return true; }
};

void doA(A a) {}

void doB(B b) {}

int main()
{
    A a1(1);        // OK:直接初始化
    A a2 = 1;       // OK:復(fù)制初始化
    A a3{ 1 };      // OK:直接列表初始化
    A a4 = { 1 };       // OK:復(fù)制列表初始化
    A a5 = (A)1;        // OK:允許 static_cast 的顯式轉(zhuǎn)換
    doA(1);         // OK:允許從 int 到 A 的隱式轉(zhuǎn)換
    if (a1);        // OK:使用轉(zhuǎn)換函數(shù) A::operator bool() 的從 A 到 bool 的隱式轉(zhuǎn)換
    bool a6(a1);        // OK:使用轉(zhuǎn)換函數(shù) A::operator bool() 的從 A 到 bool 的隱式轉(zhuǎn)換
    bool a7 = a1;       // OK:使用轉(zhuǎn)換函數(shù) A::operator bool() 的從 A 到 bool 的隱式轉(zhuǎn)換
    bool a8 = static_cast<bool>(a1);  // OK :static_cast 進(jìn)行直接初始化

    B b1(1);        // OK:直接初始化
    B b2 = 1;       // 錯(cuò)誤:被 explicit 修飾構(gòu)造函數(shù)的對(duì)象不可以復(fù)制初始化
    B b3{ 1 };      // OK:直接列表初始化
    B b4 = { 1 };       // 錯(cuò)誤:被 explicit 修飾構(gòu)造函數(shù)的對(duì)象不可以復(fù)制列表初始化
    B b5 = (B)1;        // OK:允許 static_cast 的顯式轉(zhuǎn)換
    doB(1);         // 錯(cuò)誤:被 explicit 修飾構(gòu)造函數(shù)的對(duì)象不可以從 int 到 B 的隱式轉(zhuǎn)換
    if (b1);        // OK:被 explicit 修飾轉(zhuǎn)換函數(shù) B::operator bool() 的對(duì)象可以從 B 到 bool 的按語(yǔ)境轉(zhuǎn)換
    bool b6(b1);        // OK:被 explicit 修飾轉(zhuǎn)換函數(shù) B::operator bool() 的對(duì)象可以從 B 到 bool 的按語(yǔ)境轉(zhuǎn)換
    bool b7 = b1;       // 錯(cuò)誤:被 explicit 修飾轉(zhuǎn)換函數(shù) B::operator bool() 的對(duì)象不可以隱式轉(zhuǎn)換
    bool b8 = static_cast<bool>(b1);  // OK:static_cast 進(jìn)行直接初始化

    return 0;
}

四十三.friend友元類和友元函數(shù)

  • 能訪問(wèn)私有成員揽趾、破壞封裝性、友元關(guān)系不可傳遞苛骨、友元關(guān)系的單向性篱瞎、友元聲明的形式及數(shù)量不受限制

四十四.:: 范圍解析運(yùn)算符

  • 種類:
    • 全局作用域符(::name):用于類型名稱(類误算、類成員佑女、成員函數(shù)谦纱、變量等)前加袋,表示作用域?yàn)槿置臻g
    • 類作用域符(class::name):用于表示指定類型的作用域范圍是具體某個(gè)類的
    • 命名空間作用域符(namespace::name):用于表示指定類型的作用域范圍是具體某個(gè)命名空間的
  • 使用實(shí)例:
    int count = 0;        // 全局(::)的 count
    
    class A {
    public:
        static int count; // 類 A 的 count(A::count)
    };
    
    int main() {
        ::count = 1;      // 設(shè)置全局的 count 的值為 1
    
        A::count = 2;     // 設(shè)置類 A 的 count 為 2
    
        int count = 0;    // 局部的 count
        count = 3;        // 設(shè)置局部的 count 的值為 3
    
        return 0;
    }
    

四十五.enum枚舉類型

  • 限定作用域的枚舉類型:
    enum class open_modes { input, output, append };
    
  • 不限定作用域的枚舉類型:
    enum color { red, yellow, green };
    enum { floatPrec = 6, doublePrec = 10 };
    

四十六.decltype關(guān)鍵字

  • 作用和用法:用于檢查實(shí)體的聲明類型或表達(dá)式的類型及值分類壤圃。語(yǔ)法:decltype ( expression )
  • decltype實(shí)例如下:
    // 尾置返回允許我們?cè)趨?shù)列表之后聲明返回類型
    template <typename It>
    auto fcn(It beg, It end) -> decltype(*beg)
    {
        // 處理序列
        return *beg;    // 返回序列中一個(gè)元素的引用
    }
    // 為了使用模板參數(shù)成員骡和,必須用 typename
    template <typename It>
    auto fcn2(It beg, It end) -> typename remove_reference<decltype(*beg)>::type
    {
        // 處理序列
        return *beg;    // 返回序列中一個(gè)元素的拷貝
    }
    

四十七.引用和宏

  • 左值引用:常規(guī)引用锥涕,一般表示對(duì)象的身份
  • 右值引用:右值引用就是必須綁定到右值(一個(gè)臨時(shí)對(duì)象扶认、將要銷毀的對(duì)象)的引用请琳,一般表示對(duì)象的值粱挡;右值引用可實(shí)現(xiàn)轉(zhuǎn)移語(yǔ)義(Move Sementics)和精確傳遞(Perfect Forwarding),它的主要目的有兩個(gè)方面:
    • 消除兩個(gè)對(duì)象交互時(shí)不必要的對(duì)象拷貝单起,節(jié)省運(yùn)算存儲(chǔ)資源抱怔,提高效率。
    • 能夠更簡(jiǎn)潔明確地定義泛型函數(shù)嘀倒。
  • 引用折疊: X& &屈留、X& &&、X&& & 可折疊成 X&测蘑;X&& && 可折疊成 X&&
  • 宏:宏定義可以實(shí)現(xiàn)類似于函數(shù)的功能灌危,但是它終歸不是函數(shù),而宏定義中括弧中的“參數(shù)”也不是真的參數(shù)碳胳,在宏展開的時(shí)候?qū)?“參數(shù)” 進(jìn)行的是一對(duì)一的替換勇蝙。

四十八.必須使用成員初始化列表的場(chǎng)合

  • 好處:更高效:少了一次調(diào)用默認(rèn)構(gòu)造函數(shù)的過(guò)程。
  • 有些場(chǎng)合必須要用初始化列表:
    • 常量成員挨约,因?yàn)槌A恐荒艹跏蓟荒苜x值味混,所以必須放在初始化列表里面
    • 引用類型产雹,引用必須在定義的時(shí)候初始化,并且不能重新賦值翁锡,所以也要寫在初始化列表里面
    • 沒(méi)有默認(rèn)構(gòu)造函數(shù)的類類型蔓挖,因?yàn)槭褂贸跏蓟斜砜梢圆槐卣{(diào)用默認(rèn)構(gòu)造函數(shù)來(lái)初始化

四十九.面向?qū)ο笕筇卣?/h4>
  • 封裝:把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對(duì)象操作馆衔,對(duì)不可信的進(jìn)行信息隱藏瘟判。關(guān)鍵字:public, protected, private。不寫默認(rèn)為 private角溃。
    • public 成員:可以被任意實(shí)體訪問(wèn)
    • protected 成員:只允許被子類及本類的成員函數(shù)訪問(wèn)
    • private 成員:只允許被本類的成員函數(shù)拷获、友元類或友元函數(shù)訪問(wèn)
  • 繼承:基類(父類)——> 派生類(子類)
  • 多態(tài):即多種狀態(tài)(形態(tài))。簡(jiǎn)單來(lái)說(shuō)减细,我們可以將多態(tài)定義為消息以多種形式顯示的能力匆瓜。多態(tài)是以封裝和繼承為基礎(chǔ)的
    • C++ 多態(tài)分類及實(shí)現(xiàn):
      • 重載多態(tài)(Ad-hoc Polymorphism邪财,編譯期):函數(shù)重載陕壹、運(yùn)算符重載
      • 子類型多態(tài)(Subtype Polymorphism,運(yùn)行期):虛函數(shù)
      • 參數(shù)多態(tài)性(Parametric Polymorphism树埠,編譯期):類模板糠馆、函數(shù)模板
      • 強(qiáng)制多態(tài)(Coercion Polymorphism,編譯期/運(yùn)行期):基本類型轉(zhuǎn)換怎憋、自定義類型轉(zhuǎn)換
    • 靜態(tài)多態(tài)(編譯期/早綁定)
      • 函數(shù)重載實(shí)例:
        class A
        {
        public:
            void do(int a);
            void do(int a, int b);
        };
        
    • 動(dòng)態(tài)多態(tài)(運(yùn)行期/晚綁定)
      • 虛函數(shù):用 virtual 修飾成員函數(shù)又碌,使其成為虛函數(shù)
      • 注意:
        • 普通函數(shù)(非類成員函數(shù))不能是虛函數(shù)
        • 靜態(tài)函數(shù)(static)不能是虛函數(shù)
        • 構(gòu)造函數(shù)不能是虛函數(shù)(因?yàn)樵谡{(diào)用構(gòu)造函數(shù)時(shí),虛表指針并沒(méi)有在對(duì)象的內(nèi)存空間中绊袋,必須要構(gòu)造函數(shù)調(diào)用完成后才會(huì)形成虛表指針)
        • 內(nèi)聯(lián)函數(shù)不能是表現(xiàn)多態(tài)性時(shí)的虛函數(shù)
      • 動(dòng)態(tài)多態(tài)實(shí)例
        class Shape                     // 形狀類
        {
        public:
            virtual double calcArea()
            {
                ...
            }
            virtual ~Shape();
        };
        class Circle : public Shape     // 圓形類
        {
        public:
            virtual double calcArea();
            ...
        };
        class Rect : public Shape       // 矩形類
        {
        public:
            virtual double calcArea();
            ...
        };
        int main()
        {
            Shape * shape1 = new Circle(4.0);
            Shape * shape2 = new Rect(5.0, 6.0);
            shape1->calcArea();         // 調(diào)用圓形類里面的方法
            shape2->calcArea();         // 調(diào)用矩形類里面的方法
            delete shape1;
            shape1 = nullptr;
            delete shape2;
            shape2 = nullptr;
            return 0;
        }
        

五十.虛析構(gòu)函數(shù)

  • 虛析構(gòu)函數(shù)是為了解決基類的指針指向派生類對(duì)象毕匀,并用基類的指針刪除派生類對(duì)象。
  • 虛析構(gòu)函數(shù)的使用如下:
    class Shape
    {
    public:
        Shape();                    // 構(gòu)造函數(shù)不能是虛函數(shù)
        virtual double calcArea();
        virtual ~Shape();           // 虛析構(gòu)函數(shù)
    };
    class Circle : public Shape     // 圓形類
    {
    public:
        virtual double calcArea();
        ...
    };
    int main()
    {
        Shape * shape1 = new Circle(4.0);
        shape1->calcArea();
        delete shape1;  // 因?yàn)镾hape有虛析構(gòu)函數(shù)癌别,所以delete釋放內(nèi)存時(shí)皂岔,先調(diào)用子類析構(gòu)函數(shù),再調(diào)用基類析構(gòu)函數(shù)展姐,防止內(nèi)存泄漏躁垛。
        shape1 = NULL;
        return 0;
    }
    

五十一.純虛函數(shù)

  • 定義:純虛函數(shù)是一種特殊的虛函數(shù)圾笨,在基類中不能對(duì)虛函數(shù)給出有意義的實(shí)現(xiàn)教馆,而把它聲明為純虛函數(shù),它的實(shí)現(xiàn)留給該基類的派生類去做擂达。
  • 用法: virtual int A() = 0;

五十二.虛函數(shù)土铺、純虛函數(shù)

  • 類里如果聲明了虛函數(shù),這個(gè)函數(shù)是實(shí)現(xiàn)的,哪怕是空實(shí)現(xiàn)悲敷,它的作用就是為了能讓這個(gè)函數(shù)在它的子類里面可以被覆蓋究恤,這樣的話,編譯器就可以使用后期綁定來(lái)達(dá)到多態(tài)了后德。純虛函數(shù)只是一個(gè)接口丁溅,是個(gè)函數(shù)的聲明而已,它要留到子類里去實(shí)現(xiàn)探遵。
  • 虛函數(shù)在子類里面也可以不重載的;但純虛函數(shù)必須在子類去實(shí)現(xiàn)妓柜。
  • 虛函數(shù)的類用于 “實(shí)作繼承”箱季,繼承接口的同時(shí)也繼承了父類的實(shí)現(xiàn)。當(dāng)然大家也可以完成自己的實(shí)現(xiàn)棍掐。純虛函數(shù)關(guān)注的是接口的統(tǒng)一性藏雏,實(shí)現(xiàn)由子類完成。
  • 帶純虛函數(shù)的類叫抽象類作煌,這種類不能直接生成對(duì)象掘殴,而只有被繼承,并重寫其虛函數(shù)后粟誓,才能使用奏寨。抽象類被繼承后,子類可以繼續(xù)是抽象類鹰服,也可以是普通類病瞳。
  • 虛基類是虛繼承中的基類。

五十三.虛函數(shù)指針悲酷、虛函數(shù)表

  • 虛函數(shù)指針:在含有虛函數(shù)類的對(duì)象中套菜,指向虛函數(shù)表,在運(yùn)行時(shí)確定设易。
  • 虛函數(shù)表:在程序只讀數(shù)據(jù)段逗柴,存放虛函數(shù)指針,如果派生類實(shí)現(xiàn)了基類的某個(gè)虛函數(shù)顿肺,則在虛函數(shù)表中覆蓋原本基類的那個(gè)虛函數(shù)指針戏溺,在編譯時(shí)根據(jù)類的聲明創(chuàng)建。

五十四.虛繼承

  • 用途:用于解決多繼承條件下的菱形繼承問(wèn)題(浪費(fèi)存儲(chǔ)空間挟冠、存在二義性)
  • 底層實(shí)現(xiàn)原理與編譯器相關(guān)于购,一般通過(guò)虛基類指針和虛基類表實(shí)現(xiàn),每個(gè)虛繼承的子類都有一個(gè)虛基類指針(占用一個(gè)指針的存儲(chǔ)空間知染,4字節(jié))和虛基類表(不占用類對(duì)象的存儲(chǔ)空間)(需要強(qiáng)調(diào)的是肋僧,虛基類依舊會(huì)在子類里面存在拷貝,只是僅僅最多存在一份而已,并不是不在子類里面了)嫌吠;當(dāng)虛繼承的子類被當(dāng)做父類繼承時(shí)止潘,虛基類指針也會(huì)被繼承。實(shí)際上辫诅,vbptr 指的是虛基類表指針(virtual base table pointer)凭戴,該指針指向了一個(gè)虛基類表(virtual table),虛表中記錄了虛基類與本類的偏移地址炕矮;通過(guò)偏移地址么夫,這樣就找到了虛基類成員,而虛繼承也不用像普通多繼承那樣維持著公共基類(虛基類)的兩份同樣的拷貝肤视,節(jié)省了存儲(chǔ)空間档痪。

五十五.虛繼承、虛函數(shù)

  • 相同點(diǎn):都利用了虛指針(均占用類的存儲(chǔ)空間)和虛表(均不占用類的存儲(chǔ)空間)
  • 不同點(diǎn):
    • 虛繼承:
      • 虛基類依舊存在繼承類中邢滑,只占用存儲(chǔ)空間
      • 虛基類表存儲(chǔ)的是虛基類相對(duì)直接繼承類的偏移
    • 虛函數(shù):
      • 虛函數(shù)不占用存儲(chǔ)空間
      • 虛函數(shù)表存儲(chǔ)的是虛函數(shù)地址

五十六.模板類腐螟、成員模板、虛函數(shù)

  • 模板類中可以使用虛函數(shù)
  • 一個(gè)類(無(wú)論是普通類還是類模板)的成員模板(本身是模板的成員函數(shù))不能是虛函數(shù)

五十七.抽象類困后、接口類乐纸、聚合類

  • 抽象類:含有純虛函數(shù)的類
  • 接口類:僅含有純虛函數(shù)的抽象類
  • 聚合類:用戶可以直接訪問(wèn)其成員,并且具有特殊的初始化語(yǔ)法形式摇予。滿足如下特點(diǎn):
    • 所有成員都是 public
    • 沒(méi)有定義任何構(gòu)造函數(shù)
    • 沒(méi)有類內(nèi)初始化
    • 沒(méi)有基類汽绢,也沒(méi)有 virtual 函數(shù)

五十八.內(nèi)存分配和管理

  • malloc、calloc趾盐、realloc庶喜、alloca
    • malloc:申請(qǐng)指定字節(jié)數(shù)的內(nèi)存。申請(qǐng)到的內(nèi)存中的初始值不確定救鲤。
    • calloc:為指定長(zhǎng)度的對(duì)象久窟,分配能容納其指定個(gè)數(shù)的內(nèi)存。申請(qǐng)到的內(nèi)存的每一位(bit)都初始化為 0本缠。
    • realloc:更改以前分配的內(nèi)存長(zhǎng)度(增加或減少)斥扛。當(dāng)增加長(zhǎng)度時(shí),可能需將以前分配區(qū)的內(nèi)容移到另一個(gè)足夠大的區(qū)域丹锹,而新增區(qū)域內(nèi)的初始值則不確定稀颁。
    • alloca:在棧上申請(qǐng)內(nèi)存。程序在出棧的時(shí)候楣黍,會(huì)自動(dòng)釋放內(nèi)存匾灶。但是需要注意的是,alloca 不具可移植性, 而且在沒(méi)有傳統(tǒng)堆棧的機(jī)器上很難實(shí)現(xiàn)租漂。alloca 不宜使用在必須廣泛移植的程序中阶女。C99 中支持變長(zhǎng)數(shù)組 (VLA)颊糜,可以用來(lái)替代 alloca。
  • malloc和free
    • 用途:用于分配秃踩、釋放內(nèi)存
    • 使用:
      • 申請(qǐng)內(nèi)存衬鱼,確認(rèn)是否申請(qǐng)成功
        char *str = (char*) malloc(100);
        assert(str != nullptr);
        
      • 釋放內(nèi)存后指針置空
        free(p);
        p = nullptr;
        
  • new和delete
    • new / new[]:完成兩件事,先底層調(diào)用 malloc 分配了內(nèi)存憔杨,然后調(diào)用構(gòu)造函數(shù)(創(chuàng)建對(duì)象)鸟赫。
    • delete/delete[]:也完成兩件事,先調(diào)用析構(gòu)函數(shù)(清理資源)消别,然后底層調(diào)用 free 釋放空間抛蚤。
    • new 在申請(qǐng)內(nèi)存時(shí)會(huì)自動(dòng)計(jì)算所需字節(jié)數(shù),而 malloc 則需我們自己輸入申請(qǐng)內(nèi)存空間的字節(jié)數(shù)寻狂。
    • 使用:
      int main()
      {
          T* t = new T();     // 先內(nèi)存分配 霉颠,再構(gòu)造函數(shù)
          delete t;           // 先析構(gòu)函數(shù),再內(nèi)存釋放
          return 0;
      }
      

五十九.delete this 合法嗎荆虱?

  • 合法,但是:
    • 必須保證 this 對(duì)象是通過(guò) new(不是 new[]朽们、不是 placement new怀读、不是棧上、不是全局骑脱、不是其他對(duì)象成員)分配的
    • 必須保證調(diào)用 delete this 的成員函數(shù)是最后一個(gè)調(diào)用 this 的成員函數(shù)
    • 必須保證成員函數(shù)的 delete this 后面沒(méi)有調(diào)用 this 了
    • 必須保證 delete this 后沒(méi)有人使用了

六十.如何定義一個(gè)只能在堆上(棧上)生成對(duì)象的類菜枷?

  • 只能在堆上
    • 方法: 將析構(gòu)函數(shù)設(shè)置為私有
    • 原因:C++ 是靜態(tài)綁定語(yǔ)言,編譯器管理?xiàng)I蠈?duì)象的生命周期叁丧,編譯器在為類對(duì)象分配椘√埽空間時(shí),會(huì)先檢查類的析構(gòu)函數(shù)的訪問(wèn)性拥娄。若析構(gòu)函數(shù)不可訪問(wèn)蚊锹,則不能在棧上創(chuàng)建對(duì)象。
  • 只能在棧上
    • 方法:將 new 和 delete 重載為私有
    • 原因: 在堆上生成對(duì)象稚瘾,使用 new 關(guān)鍵詞操作牡昆,其過(guò)程分為兩階段:第一階段,使用 new 在堆上尋找可用內(nèi)存摊欠,分配給對(duì)象丢烘;第二階段,調(diào)用構(gòu)造函數(shù)生成對(duì)象些椒。將 new 操作設(shè)置為私有播瞳,那么第一階段就無(wú)法完成,就不能夠在堆上生成對(duì)象免糕。

六十一.強(qiáng)制類型轉(zhuǎn)換運(yùn)算符(4種)

  • static_cast
    • 特點(diǎn):靜態(tài)轉(zhuǎn)換赢乓,在編譯處理期間忧侧。
    • 應(yīng)用場(chǎng)合: 主要用于C++中內(nèi)置的基本數(shù)據(jù)類型之間的轉(zhuǎn)換,但是沒(méi)有運(yùn)行時(shí)類型的檢測(cè)來(lái)保證轉(zhuǎn)換的安全性骏全。
      • a.用于基類和子類之間的指針或引用之間的轉(zhuǎn)換苍柏,這種轉(zhuǎn)換把子類的指針或引用轉(zhuǎn)換為基類表示是安全的;進(jìn)行下行轉(zhuǎn)換姜贡,把積累的指針或引用轉(zhuǎn)換為子類表示時(shí)试吁,由于沒(méi)有進(jìn)行動(dòng)態(tài)類型檢測(cè),所以是不安全的楼咳。
      • b.把void類型的指針轉(zhuǎn)換成目標(biāo)類型的指針(不安全)
      • c.不能用于兩個(gè)不相關(guān)的類型轉(zhuǎn)換
      • d.不能把const對(duì)象轉(zhuǎn)換成非const對(duì)象
  • const_cast
    • 特點(diǎn):去常轉(zhuǎn)換熄捍,編譯時(shí)執(zhí)行。
    • 應(yīng)用場(chǎng)合: const_cast操作不能在不同的種類間轉(zhuǎn)換母怜。相反余耽,它僅僅把它作用的表達(dá)式轉(zhuǎn)換成常量。它可以使一個(gè)本來(lái)不是const類型的數(shù)據(jù)轉(zhuǎn)換成const類型的苹熏,或者把const屬性去掉碟贾。
  • reinterpret_cast:
    • 特點(diǎn):重解釋類型轉(zhuǎn)換
    • 應(yīng)用場(chǎng)合: 它有著和c風(fēng)格強(qiáng)制類型轉(zhuǎn)換同樣的功能;它可以轉(zhuǎn)化任何的內(nèi)置數(shù)據(jù)類型為其他的類型轨域,同時(shí)它也可以把任何類型的指針轉(zhuǎn)化為其他的類型袱耽;它的機(jī)理是對(duì)二進(jìn)制進(jìn)行重新的解釋,不會(huì)改變?cè)瓉?lái)的格式干发。
  • dynamic_cast < type-id > ( expression )
    • 特點(diǎn):該運(yùn)算符將expression轉(zhuǎn)換成type_id類型的對(duì)象朱巨。type_id必須是類的指針,類的引用或者空類型的指針枉长。
    • 應(yīng)用場(chǎng)合:
      • a.如果type_id是一個(gè)指針類型冀续,那么expression也必須是一個(gè)指針類型,如果type_id是一個(gè)引用類型必峰,那么expression也必須是一個(gè)引用類型洪唐。
      • b.如果type_id是一個(gè)空類型的指針,在運(yùn)行的時(shí)候吼蚁,就會(huì)檢測(cè)expression的實(shí)際類型桐罕,結(jié)果是一個(gè)由expression決定的指針類型。
      • c.如果type_id不是空類型的指針桂敛,在運(yùn)行的時(shí)候指向expression對(duì)象的指針能否可以轉(zhuǎn)換成type_id類型的指針
      • d.在運(yùn)行的時(shí)候決定真正的類型功炮,如果向下轉(zhuǎn)換是安全的,就返回一個(gè)轉(zhuǎn)換后的指針术唬,若不安全薪伏,則返回一個(gè)空指針
      • e.主要用于上下行之間的轉(zhuǎn)換,也可以用于類之間的交叉轉(zhuǎn)換粗仓。上行轉(zhuǎn)換時(shí)和static_cast效果一樣嫁怀,下行轉(zhuǎn)換時(shí)设捐,具有檢測(cè)功能,比static_cast更安全塘淑。

六十二.new delete和malloc free的聯(lián)系和區(qū)別

  • malloc與free是C語(yǔ)言的標(biāo)準(zhǔn)庫(kù)函數(shù)萝招, new/delete是C++的運(yùn)算符。它們都可用于申請(qǐng)動(dòng)態(tài)內(nèi)存和釋放內(nèi)存;
  • 對(duì)于非內(nèi)部數(shù)據(jù)類型的對(duì)象而言存捺,光用maloc/free無(wú)法滿足動(dòng)態(tài)對(duì)象的要求槐沼。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)
    造函數(shù),對(duì)象在消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù)捌治。由于malloc/free是庫(kù)函數(shù)而不是運(yùn)算符岗钩,不在編譯器控制權(quán)限之
    內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加于malloc/free;
  • C++語(yǔ)言需要一個(gè)能完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new肖油,以一個(gè)能完成清理與釋放內(nèi)存工作的運(yùn)算符delete兼吓,注意new/delete不是庫(kù)函數(shù)。

六十三.hash沖突及解決方法

  • 關(guān)鍵字值不同的元素可能會(huì)映射到哈希表的同一地址上就會(huì)發(fā)生哈希沖突森枪。解決辦法:
    • 開放定址法:當(dāng)沖突發(fā)生時(shí)视搏,使用某種探查(亦稱探測(cè))技術(shù)在散列表中形成一個(gè)探查(測(cè))序列。沿此序列逐個(gè)單元地查找县袱,直到找到給定 的關(guān)鍵字凶朗,或者碰到一個(gè)開放的地址(即該地址單元為空)為止(若要插入,在探查到開放的地址显拳,則可將待插入的新結(jié)點(diǎn)存人該地址單元)。查找時(shí)探查到開放的 地址則表明表中無(wú)待查的關(guān)鍵字搓萧,即查找失敗杂数。
    • 再哈希法:同時(shí)構(gòu)造多個(gè)不同的哈希函數(shù)
    • 鏈地址法:將所有哈希地址為 i 的元素構(gòu)成一個(gè)稱為同義詞鏈的單鏈表,并將單鏈表的頭指針存在哈希表的第 i 個(gè)
      單元中瘸洛,因而查找揍移、插入和刪除主要在同義詞鏈中進(jìn)行。鏈地址法適用于經(jīng)常進(jìn)行插入和刪除的情況
    • 建立公共溢出區(qū):將哈希表分為基本表和溢出表兩部分反肋,凡是和基本表發(fā)生沖突的元素那伐,一律填入溢出表。

六十四.多態(tài)是什么,多態(tài)的作用石蔗?

  • 定義:同一個(gè)對(duì)象罕邀,在不同時(shí)刻體現(xiàn)出來(lái)的不同狀態(tài)。
  • 多態(tài)的前提:
    • 要有繼承關(guān)系或?qū)崿F(xiàn)關(guān)系(接口)
    • 要有方法重寫养距;
    • 要有父類或者父接口引用指向子類Base b= new Derived()诉探;
  • 作用:提高了代碼的維護(hù)性(繼承保證);提高了代碼的擴(kuò)展性

六十五. 繼承含有純虛函數(shù)的父類棍厌,子類能否實(shí)例化肾胯?

  • 如果父類中存在純虛函數(shù)竖席,子類繼承父類時(shí),必須重寫父類的純虛函數(shù)敬肚,函數(shù)名毕荐、返回類型、參數(shù)個(gè)數(shù)和類型都不能改艳馒。若父類中的虛函數(shù)自己有定義憎亚,子類也可以不重寫。之后便可以實(shí)例化子類鹰溜。

六十六.構(gòu)造函數(shù)是否可以用private修飾虽填,如果可以,會(huì)有什么效果曹动?

  • 如果一個(gè)類的構(gòu)造函數(shù)只有一個(gè)且為private斋日,這是可以編譯通過(guò)的;
  • 如果一個(gè)類的構(gòu)造函數(shù)只有一個(gè)且是private墓陈,如果類的內(nèi)部沒(méi)有專門創(chuàng)建實(shí)例的代碼恶守,則是無(wú)法創(chuàng)建任何實(shí)例的;
  • 如果一個(gè)類的構(gòu)造函數(shù)只有一個(gè)且是private贡必,如果類的內(nèi)部有專門創(chuàng)建實(shí)例的代碼兔港,則只能創(chuàng)建一個(gè)或多個(gè)實(shí)例(根據(jù)類內(nèi)部聲明的成員對(duì)象個(gè)數(shù)來(lái)定);
  • 如果一個(gè)類的構(gòu)造函數(shù)不止一個(gè)仔拟,private 構(gòu)造函數(shù)如果參數(shù) 為void(無(wú)參)衫樊,則子類無(wú)法編譯;換言之利花,如果一個(gè)類構(gòu)造函數(shù)只有private且存在子類科侈,則無(wú)法編譯,除非父類構(gòu)造函數(shù)為public炒事。

六十七.子類的指針能否轉(zhuǎn)換為父類的指針臀栈?父類指針能否訪問(wèn)子類成員?

  • 當(dāng)自己的類指針指向自己類的對(duì)象時(shí)挠乳,無(wú)論調(diào)用的是虛函數(shù)還是實(shí)函數(shù)权薯,其調(diào)用的都是自己的
  • 當(dāng)指向父類對(duì)象的父類指針被強(qiáng)制轉(zhuǎn)換成子類指針時(shí)候,子類指針調(diào)用函數(shù)時(shí)睡扬,只有非重寫函數(shù)是自己的盟蚣,虛函數(shù)是父類的;
  • 當(dāng)指向子類對(duì)象的子類指針被強(qiáng)制轉(zhuǎn)換成父類指針的時(shí)候卖怜,也就是父類指針指向子類對(duì)象刁俭,此時(shí),父類指針調(diào)用的虛函數(shù)都是子類的韧涨,而非虛函數(shù)都是自己的牍戚;

六十八.虛函數(shù)的實(shí)現(xiàn)機(jī)制

六十九.vector與list的區(qū)別

  • 1.vector擁有一段連續(xù)的內(nèi)存空間侮繁,因此支持隨機(jī)存取。如果需要高效的隨機(jī)存取如孝,而不在乎插入和刪除的效率宪哩,使用vector。vector和數(shù)組類似第晰,它擁有一段連續(xù)的內(nèi)存空間锁孟,并且起始地址不變,因此它能非常好的支持隨機(jī)存取茁瘦,但由于它的內(nèi)存空間是連續(xù)的品抽,所以在中間進(jìn)行插入和刪除會(huì)造成內(nèi)存塊的拷貝。另外甜熔,當(dāng)該數(shù)組后的內(nèi)存空間不夠時(shí)圆恤,需要重新申請(qǐng)一塊足夠大的內(nèi)存并進(jìn)行內(nèi)存的拷貝,這影響vector的效率腔稀。
  • 2.list擁有一段不連續(xù)的內(nèi)存空間盆昙,因此不支持隨機(jī)存取。如果需要大量的插入和刪除焊虏,而不關(guān)心隨機(jī)存取淡喜,則應(yīng)使用list。list是由數(shù)據(jù)結(jié)構(gòu)中的雙向鏈表實(shí)現(xiàn)的诵闭,因此它的內(nèi)存空間可以是不連續(xù)的炼团。因此只能通過(guò)指針來(lái)進(jìn)行數(shù)據(jù)的訪問(wèn),這個(gè)特點(diǎn)使得它的隨機(jī)存取變得非常沒(méi)有效率疏尿,需要遍歷中間的元素瘟芝。但由于鏈表的特點(diǎn),它可以很好的效率支持任意地方的刪除和插入润歉。

七十.vector的底層實(shí)現(xiàn)

  • vector的底層數(shù)據(jù)結(jié)構(gòu)是一個(gè)動(dòng)態(tài)數(shù)組。默認(rèn)構(gòu)造的大小是0颈抚,之后插入按照1 2 4 8 16二倍擴(kuò)容踩衩。擴(kuò)容后是一片新的內(nèi)存,需要把舊內(nèi)存空間中的所有元素都拷貝進(jìn)新內(nèi)存空間中去贩汉,之后再在新內(nèi)存空間中的原數(shù)據(jù)的后面繼續(xù)進(jìn)行插入構(gòu)造新元素驱富,并且同時(shí)釋放舊內(nèi)存空間。并且匹舞,由于vector空間的重新配置褐鸥,導(dǎo)致舊vector的所有迭代器都失效了。vector的初始的擴(kuò)容方式代價(jià)太大赐稽,初始擴(kuò)容效率低叫榕,需要頻繁增長(zhǎng)浑侥。不僅操作效率比較低,而且頻繁的向操作系統(tǒng)申請(qǐng)內(nèi)存容易造成過(guò)多的內(nèi)存碎片晰绎,所以這個(gè)時(shí)候需要合理使用resize()和reserve()方法提高效率減少內(nèi)存碎片寓落。

七十一.函數(shù)參數(shù)壓棧方式為什么是從右到左的?

  • 因?yàn)镃++支持可變函數(shù)參數(shù)荞下。正是這個(gè)原因使得C語(yǔ)言函數(shù)參數(shù)入棧順序是從右到左伶选。具體是:C方式參數(shù)入棧順序的好處就是可以動(dòng)態(tài)變化參數(shù)個(gè)數(shù)。C程序棧底為高地址尖昏,棧頂為低地址仰税。函數(shù)最左邊確定的參數(shù)在棧上的位置必須是確定的,否則意味著已經(jīng)確定的參數(shù)是不能定位和找到的抽诉,這樣式無(wú)法保證函數(shù)正確執(zhí)行的陨簇。衡量參數(shù)在棧上的位置,就是離開確切的函數(shù)調(diào)用點(diǎn)有多遠(yuǎn)掸鹅。已經(jīng)確定的參數(shù)塞帐,它在棧上的位置,不應(yīng)該依賴參數(shù)的具體數(shù)量巍沙,因此參數(shù)數(shù)量是未知的葵姥!所有只有確定的參數(shù)最后入棧才能保證它在棧中的位置是確定的。

七十二.動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)對(duì)比

  • 靜態(tài)庫(kù):靜態(tài)庫(kù)對(duì)函數(shù)庫(kù)的鏈接是放在編譯時(shí)期完成的句携,程序在運(yùn)行時(shí)與函數(shù)庫(kù)沒(méi)有關(guān)系榔幸,便于移植。缺點(diǎn)是:浪費(fèi)空間和資源矮嫉,因?yàn)樗邢嚓P(guān)的目標(biāo)文件與牽涉到的函數(shù)庫(kù)被鏈接合成一個(gè)可執(zhí)行文件削咆。文件后綴常為(.a、.lib)
  • 動(dòng)態(tài)庫(kù):動(dòng)態(tài)庫(kù)把對(duì)一些庫(kù)函數(shù)的鏈接載入推遲到程序運(yùn)行的時(shí)期蠢笋〔ζ耄可以實(shí)現(xiàn)進(jìn)程間的資源共享,將一些程序升級(jí)變的簡(jiǎn)單昨寞,直接更改動(dòng)態(tài)庫(kù)即可瞻惋。文件后綴常為(.s0、.dll)

七十三.預(yù)編譯階段的具體流程

  • 預(yù)編譯也稱為預(yù)處理援岩,是做些代碼文本的替換工作歼狼。主要處理#開頭的指令,比如拷貝#include包含的文件代碼享怀,#define宏定義的替換羽峰,條件編譯,就是為編譯做預(yù)備工作的階段∶诽耄可執(zhí)行文件編譯過(guò)程:


    編譯過(guò)程

七十四.黑盒測(cè)試與白盒測(cè)試

  • 白盒測(cè)試:通過(guò)程序的源代碼進(jìn)行測(cè)試而不使用用戶界面值纱。這種類型的測(cè)試需要從代碼句法發(fā)現(xiàn)內(nèi)部代碼在算法、溢出履植、路徑计雌、條件等等中的缺點(diǎn)或者錯(cuò)誤,進(jìn)而加以修正玫霎。
  • 黑盒測(cè)試:通過(guò)使用整個(gè)軟件或某種軟件功能來(lái)嚴(yán)格地測(cè)試, 而并沒(méi)有通過(guò)檢查程序的源代碼或者很清楚地了解該軟件的源代碼程序具體是怎樣設(shè)計(jì)的凿滤。測(cè)試人員通過(guò)輸入他們的數(shù)據(jù)然后看輸出的結(jié)果從而了解軟件怎樣工作。在測(cè)試時(shí)庶近,把程序看作一個(gè)不能打開的黑盆子翁脆,在完全不考慮程序內(nèi)部結(jié)構(gòu)和內(nèi)部特性的情況下,測(cè)試者在程序接口進(jìn)行測(cè)試鼻种,它只檢查程序是否能適當(dāng)?shù)亟邮蘸驼_的輸出反番。

七十五.一個(gè)空類class中有什么?

  • 構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)叉钥、析構(gòu)函數(shù)罢缸、賦值運(yùn)算符重載、取地址操作符重載投队、被const修飾的取地址操作符重載

七十六.構(gòu)造函數(shù)和析構(gòu)函數(shù)能被繼承嗎?

  • 不能枫疆。不是所有的函數(shù)都能自動(dòng)地從基類繼承到派生類中的。構(gòu)造函數(shù)和析構(gòu)函數(shù)是用來(lái)處理對(duì)象的創(chuàng)建和析構(gòu)的敷鸦,它們只知道對(duì)在它們的特殊層次的對(duì)象做什么息楔。所以,在整個(gè)層次中的所有的構(gòu)造函數(shù)和析構(gòu)函數(shù)都必須被調(diào)用扒披,也就是說(shuō)值依,構(gòu)造函數(shù)和析構(gòu)函數(shù)不能被繼承。子類的構(gòu)造函數(shù)會(huì)顯示的調(diào)用父類的構(gòu)造函數(shù)或隱式的調(diào)用父類的默認(rèn)的構(gòu)造函數(shù)進(jìn)行父類部分的初始化碟案。析構(gòu)函數(shù)也一樣愿险。它們都是每個(gè)類都有的東西,如果能被繼承价说,那就沒(méi)有辦法初始化了辆亏。

七十七.構(gòu)造函數(shù)能不能是虛函數(shù)?

  • 不能熔任。a.創(chuàng)建一個(gè)對(duì)象必須明確指出它的類型褒链,否則無(wú)法創(chuàng)建唁情,一個(gè)對(duì)象創(chuàng)建成功編譯器獲得它的實(shí)際類型疑苔,然后去調(diào)用對(duì)應(yīng)的函數(shù),而如果構(gòu)造函數(shù)聲明為虛函數(shù)甸鸟,會(huì)形成一個(gè)死鎖惦费,虛函數(shù)是在運(yùn)行才能確定確定其調(diào)用哪一個(gè)類型的函數(shù)兵迅,而具體哪一個(gè)類型是編譯器通過(guò)對(duì)象的類型去確定的,但是此時(shí)對(duì)象還未創(chuàng)建也就沒(méi)法知道其真實(shí)類型薪贫。b.虛函數(shù)對(duì)應(yīng)一張?zhí)摵瘮?shù)表恍箭,這個(gè)虛函數(shù)表是存儲(chǔ)在對(duì)象的內(nèi)存空間的,如果構(gòu)造函數(shù)是虛函數(shù)就需要通過(guò)虛函數(shù)表來(lái)調(diào)用瞧省,可是對(duì)象還沒(méi)有實(shí)例化扯夭,也就是內(nèi)存空間還沒(méi)有,找不到虛函數(shù)表鞍匾,所以構(gòu)造函數(shù)是不能聲明為虛函數(shù)的交洗。

七十八.構(gòu)造函數(shù)和析構(gòu)函數(shù)能不能被重載 ?

  • 構(gòu)造函數(shù)可以被重載橡淑,析構(gòu)函數(shù)不可以被重載构拳。因?yàn)闃?gòu)造函數(shù)可以有多個(gè)且可以帶參數(shù), 而析構(gòu)函數(shù)只能有一個(gè)梁棠,且不能帶參數(shù)置森。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市符糊,隨后出現(xiàn)的幾起案子凫海,更是在濱河造成了極大的恐慌,老刑警劉巖濒蒋,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盐碱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡沪伙,警方通過(guò)查閱死者的電腦和手機(jī)厌杜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捡絮,“玉大人榄融,你說(shuō)我怎么就攤上這事∥淌冢” “怎么了拣播?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)收擦。 經(jīng)常有香客問(wèn)我贮配,道長(zhǎng),這世上最難降的妖魔是什么塞赂? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任泪勒,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘圆存。我一直安慰自己叼旋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布沦辙。 她就那樣靜靜地躺著夫植,像睡著了一般。 火紅的嫁衣襯著肌膚如雪油讯。 梳的紋絲不亂的頭發(fā)上详民,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音陌兑,去河邊找鬼阐斜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛诀紊,可吹牛的內(nèi)容都是我干的谒出。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼邻奠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼笤喳!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碌宴,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤杀狡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后贰镣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呜象,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年碑隆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恭陡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡上煤,死狀恐怖休玩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情劫狠,我是刑警寧澤拴疤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站独泞,受9級(jí)特大地震影響呐矾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懦砂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一蜒犯、第九天 我趴在偏房一處隱蔽的房頂上張望讲坎。 院中可真熱鬧,春花似錦愧薛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至削罩,卻和暖如春瞄勾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弥激。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工进陡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人微服。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓趾疚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親以蕴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子糙麦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容