C++基礎(chǔ)
(1)C和C++的區(qū)別
C++分為:
C部分(區(qū)塊、語句佳吞、預處理器拱雏、內(nèi)置數(shù)據(jù)類型、數(shù)組底扳、指針等)铸抑;
面向?qū)ο蟮腃++特性(類、封裝衷模、繼承鹊汛、多態(tài)、動態(tài)綁定等)阱冶;
模板特性(泛型編程刁憋、元編程);
STL(容器木蹬、迭代器至耻、算法、函數(shù)對象等)镊叁;
參考:《effective C++》 條款01
(2)指針和引用
指針:存放變量地址值的變量尘颓。
引用:變量的別名。
(特性)1意系、引用定義時需要初始化泥耀,指針不用;
(特性)2蛔添、引用無法改變綁定對象痰催,指針可以;
(內(nèi)存)3迎瞧、sizeof(引用) = sizeof(type)夸溶,sizeof(ptr) = 4/8;
(3)堆和棧
棧:存放變量的特定地址空間凶硅。
堆:存放變量的特定地址空間缝裁。
(內(nèi)存)1、棧向下生長足绅;堆向上生長捷绑;
(內(nèi)存)2、棧由系統(tǒng)自動分配空間氢妈,機器底層級別提供支持(方式)粹污,空間固定較小~2M,內(nèi)存利用率更高(效率)首量;堆由malloc壮吩、new控制进苍,C/C++庫函數(shù)級別提供支持,空間更大鸭叙,鏈表管理觉啊,容易產(chǎn)生碎片;
參考:https://blog.csdn.net/nieyibin/article/details/7468323
(4)new和delete
new:C++運算符沈贝,在堆區(qū)申請內(nèi)存杠人,返回指針。
delete:C++運算符宋下,回收指針指向內(nèi)存空間搜吧。
(執(zhí)行步驟)1、調(diào)用operator new申請內(nèi)存杨凑;2、調(diào)用構(gòu)造函數(shù)摆昧;3撩满、調(diào)用析構(gòu)函數(shù);4绅你、調(diào)用operator delete釋放內(nèi)存伺帘;
參考:https://blog.csdn.net/hihozoo/article/details/51441521
(5)new和malloc
new:C++運算符,在堆區(qū)申請內(nèi)存忌锯,返回指針伪嫁。
malloc:C庫函數(shù),在堆區(qū)申請內(nèi)存偶垮,返回指針张咳。
(特性)1、new首先申請內(nèi)存似舵,然后調(diào)用構(gòu)造函數(shù)脚猾,不需要指定內(nèi)存空間大小砚哗;malloc需要手動指定內(nèi)存空間大辛;
(特性)1蛛芥、new []/delete []用于申請/釋放數(shù)組空間提鸟;malloc沒有數(shù)組空間的概念;
(特性)2仅淑、new失敗返回bac_alloc称勋;malloc失敗返回NULL;
(安全)3漓糙、new類型安全铣缠;malloc返回void*,非類型安全;
(特性)4蝗蛙、new過程中的operator new可以重載蝇庭;malloc不能重載;
(優(yōu)化)5捡硅、operator new是操作符能經(jīng)編譯器優(yōu)化哮内;malloc是庫函數(shù),不受編譯器優(yōu)化壮韭。
參考:
https://www.cnblogs.com/QG-whz/p/5140930.html
https://chenqx.github.io/2014/09/25/Cpp-Memory-Management/
(6)struct和class的區(qū)別
struct:C語言提供的數(shù)據(jù)封裝北发;
class:C++擴展的數(shù)據(jù)封裝;
(特性):struct成員默認權(quán)限為public喷屋,struct繼承方式默認為public琳拨;class成員默認權(quán)限為private,class繼承方式默認為private屯曹;
參考:https://stackoverflow.com/questions/92859/what-are-the-differences-between-struct-and-class-in-c
(7)define 和const
define:宏定義狱庇,預處理期間進行替換;
const:關(guān)鍵字恶耽,修飾變量密任,限制變量為常量類型;
(階段)1偷俭、define為預處理期間執(zhí)行替換浪讳;const為編譯期分配內(nèi)存;
(安全)2涌萤、define不進行類型檢查淹遵;const會進行類型檢查;
(內(nèi)存)3形葬、define直接替換合呐,如果是字面值則被編譯器處理為立即數(shù),占據(jù)內(nèi)存空間不定笙以,取決于編譯器和操作系統(tǒng)淌实;const則占據(jù)靜態(tài)存儲區(qū)中的.DATA段,因為定義時需要初始化猖腕;
(使用)4拆祈、define替換的變量不好追蹤;const變量在符號表中倘感,方便追蹤放坏;
參考:
https://www.geeksforgeeks.org/diffference-define-const-c/
《effective C++》條款02
(8)static和const
const:修飾變量,表示其為常量老玛;
static:修飾變量淤年,表示變量駐留在靜態(tài)存儲區(qū)钧敞,不回收其內(nèi)存,限制其作用域麸粮;
用于變量:
(最重要)1溉苛、const全局變量作用域為所有文件(外部鏈接);static const全局變量作用域為本文件(內(nèi)部鏈接)弄诲;總結(jié):static起到了限制作用域的作用愚战;(注意,以上情況是C齐遵,在C++中const修飾全局變量默認為內(nèi)部鏈接等同于static const)
(內(nèi)存)2寂玲、const全局變量,符號表或靜態(tài)存儲區(qū).DATA梗摇;const局部變量拓哟,棧區(qū);static全局變量伶授,靜態(tài)存儲區(qū).BSS/.DATA彰檬;static局部變量,棧區(qū)谎砾;
參考:
(const變量)https://blog.csdn.net/xiazhiyiyun/article/details/71969618
(static變量)https://www.cnblogs.com/cobain/archive/2008/01/31/1060216.html
(const全局變量)http://mzorro.me/2013/04/13/diff-of-const-in-c-and-cpp/
(全局變量和局部變量)https://blog.csdn.net/qq_33266987/article/details/51965221
用于類內(nèi)部:
(特性)1、類中的static成員屬于類捧颅,也即屬于所有對象景图,也即沒有this指針;類中的const成員屬于對象/實例碉哑;
(初始化)2挚币、類中的static成員在類外初始化,且先于各個對象的初始化扣典;類中的const變量需要使用初始化列表進行初始化妆毕;
(函數(shù)成員)3、類中的static函數(shù)只能使用類中的static變量贮尖;類中的const函數(shù)表示該函數(shù)執(zhí)行不改變對象中的各個變量的值笛粘;
參考:
(static成員)https://blog.csdn.net/u014453898/article/details/64124269/
(9) 計算下面幾個類的大小:
class A {};: sizeof(A) = 1;
class A { virtual Fun(){} };:
sizeof(A) = 4(32位機器)/8(64位機器);
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;
(10)重載(overload)湿硝、覆蓋(override)薪前、隱藏(hidden)
重載:同一類中,函數(shù)名相同关斜,參數(shù)類型/數(shù)量不同示括;
覆蓋:不同類中,函數(shù)名相同痢畜,參數(shù)相同垛膝,虛函數(shù)鳍侣;
隱藏:不同類中,函數(shù)名相同吼拥,參數(shù)相同倚聚,非虛函數(shù);
? ? ? 不同類中扔罪,函數(shù)名相同秉沼,參數(shù)不同,虛函數(shù)或非虛函數(shù)矿酵;
參考:http://www.cnblogs.com/txwsh1/archive/2008/06/28/1231751.html
(11) C ++內(nèi)存分配
從C++語言角度看:
棧:存放局部變量唬复,函數(shù)執(zhí)行結(jié)束時釋放。內(nèi)存分配運算內(nèi)置于處理器的指令集中全肮,效率高敞咧,空間有限。
堆:new分配的內(nèi)存塊辜腺,由delete控制釋放休建。
自由存儲區(qū):malloc分配的內(nèi)存塊,由free控制釋放评疗。
全局/靜態(tài)存儲區(qū):存放全局變量测砂、靜態(tài)變量。C語言中百匆,全局變量分為初始化的(.DATA)和非初始化的(.BSS)砌些;C++中沒有區(qū)分。
常量存儲區(qū):存放常量加匈,不允許修改存璃。
程序代碼段:存放函數(shù)體的二進制代碼。
從linux程序的內(nèi)存映像角度看:
參考:
(基礎(chǔ)概念)https://chenqx.github.io/2014/09/25/Cpp-Memory-Management/
(基礎(chǔ)概念)https://www.cnblogs.com/dong008259/archive/2011/11/07/2239353.html
(堆雕拼、自由存儲區(qū)的區(qū)別)https://www.cnblogs.com/QG-whz/p/5060894.html
(linux內(nèi)存)https://blog.csdn.net/shanghairuoxiao/article/details/70256247
(linux內(nèi)存)http://mqzhuang.iteye.com/blog/901602
(12) 面向?qū)ο蟮娜筇匦?/b>
封裝:將數(shù)據(jù)和方法封裝到一個單元內(nèi)纵东,通過接口和外界交互,內(nèi)部對外界不可見啥寇,隱藏數(shù)據(jù)與方法偎球。
繼承:一個類的對象獲取另一個類的對象的屬性的過程。功能添加辑甜。
多態(tài):采取多種形式的能力甜橱,操作在不同的實例中表現(xiàn)出不同的行為,接口重用栈戳。C++支持運行時多態(tài)(虛函數(shù))岂傲,編譯時多態(tài)(模板/泛型、函數(shù)重載)子檀。
參考:
(概念)https://www.geeksforgeeks.org/basic-concepts-of-object-oriented-programming-using-c/
(擴展)https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html
(多態(tài))http://huqunxing.site/2016/09/08/C++%20%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7%E4%B9%8B%E5%A4%9A%E6%80%81/
(13) C++虛函數(shù)
虛函數(shù)是應在派生類中重新定義的成員函數(shù)镊掖,當指針或基類的引用用來引用派生類的對象時乃戈,可以為該對象正確調(diào)用該函數(shù)的派生類版本。
(實現(xiàn)原理)1亩进、虛指針vptr症虑,虛函數(shù)表vtable。注意:a归薛、同一類的不同對象共享一張vtable谍憔;該表在編譯期間由編譯器創(chuàng)建;b主籍、各種情況:派生類單繼承覆蓋基類虛函數(shù)习贫、派生類單繼承不覆蓋基類虛函數(shù)引入新的虛函數(shù)、派生類多繼承覆蓋基類虛函數(shù)等千元。
(特殊用法)2苫昌、抽象類/純虛函數(shù)。注意:a幸海、虛函數(shù)=0為純虛函數(shù)祟身;b、包含純虛函數(shù)的類為抽象類物独,抽象類不能實例化袜硫;
(特殊用法)3挡篓、final specifier,檢查確保父類函數(shù)為虛函數(shù),且不能重載奔類中的該函數(shù)世杀。override
specifer阀参,檢查確保是否覆蓋了父類虛函數(shù)。
參考:
(概念)https://msdn.microsoft.com/zh-cn/library/0y01k918.aspx
(虛指針和虛函數(shù)表)https://blog.twofei.com/496/
(final/override)https://en.cppreference.com/w/cpp/language/override
(14) 析構(gòu)函數(shù)一般寫成虛函數(shù)的原因
操作基類指針釋放對象內(nèi)存時蛛壳,將析構(gòu)函數(shù)寫為虛函數(shù)所刀,可以在析構(gòu)過程中首先釋放派生類部分的內(nèi)存衙荐,再依次釋放基類部分的內(nèi)存。這樣能保證銷毀整個對象同時不出現(xiàn)內(nèi)存泄漏浮创。
參考:《effective C++》條款07
(15) 構(gòu)造函數(shù)為什么一般不定義為虛函數(shù)
從原理角度:虛指針是在構(gòu)造函數(shù)執(zhí)行過程中初始化的,編譯器處理溜族,對程序員透明。如果構(gòu)造函數(shù)為虛函數(shù)仍劈,那么在開始執(zhí)行構(gòu)造函數(shù)時由于虛指針還未初始化寡壮,從而會出現(xiàn)無法定位構(gòu)造函數(shù)的錯誤情況。
從設計思想角度:虛函數(shù)的調(diào)用只需要部分的信息这溅,而不需要知道對象的具體類型坏挠;但是構(gòu)造函數(shù)需要知道具體的類型降狠。
(16) 構(gòu)造函數(shù)或者析構(gòu)函數(shù)中調(diào)用虛函數(shù)會怎樣
構(gòu)造函數(shù)中調(diào)用:可能出現(xiàn)要調(diào)用的函數(shù)未創(chuàng)建的情況,此時即視對象為基類否纬,虛函數(shù)不起作用蛋褥;基類構(gòu)造函數(shù)執(zhí)行先于派生類構(gòu)造函數(shù)執(zhí)行,調(diào)用基類構(gòu)造函數(shù)中的虛函數(shù)膜廊,意味著調(diào)用時派生類還未創(chuàng)建那么該虛函數(shù)指向的總是基類該函數(shù)而不是派生類該函數(shù);
析構(gòu)函數(shù)中調(diào)用:可能出現(xiàn)要調(diào)用的函數(shù)已經(jīng)被銷毀的情況爪瓜,此時即視對象為基類匙瘪,虛函數(shù)不起作用丹喻;
參考:《effective C++》條款09
(17) 靜態(tài)綁定和動態(tài)綁定的介紹
靜態(tài)綁定(編譯時多態(tài)):模板泛型而晒、函數(shù)重載等
動態(tài)綁定(運行時多態(tài)):虛函數(shù)等
參考:https://blog.csdn.net/iicy266/article/details/11906509
(18) 引用是否能實現(xiàn)動態(tài)綁定赐劣,為什么引用可以實現(xiàn)
引用可以實現(xiàn)赊瞬。從反匯編的角度看,引用的本質(zhì)是一個由編譯器管理的指針薯蝎。其表現(xiàn)出來的語法特征和其所引用的對象一致谤绳。
(19) 深拷貝和淺拷貝的區(qū)別(舉例說明深拷貝的安全性)
淺拷貝:復制指向?qū)ο蟮闹羔標跎福瑑蓚€指針指向同一對象;
深拷貝:復制指向?qū)ο蟮膬?nèi)存艺演,兩個指針指向兩份同樣內(nèi)容的內(nèi)存桐臊;
安全性:修改內(nèi)容断凶,淺拷貝影響兩個對象,深拷貝影響修改對應對象肿男。
(20) 對象復用的了解舶沛,零拷貝的了解
對象池:對象池通過對象復用的方式來避免重復創(chuàng)建對象窗价,它會事先創(chuàng)建一定數(shù)量的對象放到池中,當用戶需要創(chuàng)建對象的時候,直接從對象池中獲取即可餐胀,用完對象之后再放回到對象池中瘤载,以便復用鸣奔。
適用性:類的實例可重用惩阶。類的實例化過程開銷較大断楷。類的實例化的頻率較高崭别。
零拷貝:避免CPU將數(shù)據(jù)從一塊存儲拷貝到另外一塊存儲茅主,主要就是利用各種零拷貝技術(shù),避免讓CPU做大量的數(shù)據(jù)拷貝任務响牛,減少不必要的拷貝赫段,或者讓別的組件來做這一類簡單的數(shù)據(jù)傳輸任務瑞佩,讓CPU解脫出來專注于別的任務。這樣就可以讓系統(tǒng)資源的利用更加有效瘫寝。
參考:(零拷貝)http://www.reibang.com/p/fad3339e3448
(21) 介紹C++所有的構(gòu)造函數(shù)
構(gòu)造函數(shù)A(void):用于一般對象的創(chuàng)建焕阿。
拷貝構(gòu)造函數(shù)A(const A &a):作為函數(shù)的參數(shù)首启,作為函數(shù)的返回值毅桃,作為對象給另一對象初始化(A a2 = a1;使用的運算符=,實際等效于A a2(a1);)莺掠。
賦值構(gòu)造函數(shù)A& operator=(const A
&a):對象給另一對象賦值读宙。
(22) 什么情況下會調(diào)用拷貝構(gòu)造函數(shù)
函數(shù)的參數(shù)為對象。
函數(shù)的返回值為對象或?qū)ο蟮囊谩?/p>
作為對象給另一對象初始化酒朵。
參考:https://www.cnblogs.com/wangguchangqing/p/6141743.html
(23) 結(jié)構(gòu)體內(nèi)存對齊方式和為什么要進行內(nèi)存對齊扎附?
對齊規(guī)則:
1帕棉、變量開始地址為其大小的倍數(shù)。
2慰枕、結(jié)構(gòu)體大小為其最大元素大小的倍數(shù)即纲。
3低斋、#pragma pack指定后,結(jié)構(gòu)體大小為min(最大元素大小掘猿,指定值)的倍數(shù)稠通。
對齊理由:
1买猖、移植原因玉控。某些平臺只能在特定地址處取特定數(shù)據(jù)值。
2碌识、性能原因虱而。訪問未對齊的內(nèi)存薛窥,處理器需要額外的訪問次數(shù)。有的平臺從偶地址開始讀佩番,如果數(shù)據(jù)從奇地址開始讀趟畏,那么需要訪問兩次滩租。
參考:https://blog.csdn.net/jamesf1982/article/details/4375719
(24) 內(nèi)存泄露和內(nèi)存溢出
泄露:申請的內(nèi)存空間未釋放導致律想。
溢出:1、數(shù)組越界著洼。2身笤、緩沖區(qū)/椏辏空間不夠用溢出脱篙。
(25)遇到coredump要怎么調(diào)試
A core dump is a file containing aprocess's address space (memory) when the process terminates unexpectedly. Coredumps may be produced on-demand (such as by a debugger), or automatically upontermination. Core dumps are triggered by the kernel in response to programcrashes, and may be passed to a helper program (such as systemd-coredump) forfurther processing. A core dump is not typically used by an average user, butmay be passed on to developers upon request where it can be invaluable as apost-mortem snapshot of the program's state at the time of the crash,especially if the fault is hard to reliably reproduce.
參考:https://wiki.archlinux.org/index.php/Core_dump
(26) 模板的用法與適用場景
模板是C++泛型編程的基礎(chǔ)涡尘。Template 考抄。
應用場景:除了參數(shù)類型不一樣外,其他的內(nèi)容全部一樣(函數(shù)體)疯兼,用模板吧彪,而不是每一個類型都寫一個函數(shù)丢早。
特化:模板的一個獨立的定義,其中一個或多個參數(shù)被指定為特定的類型傀缩。通用模板不能適應所有情況赡艰。(特殊情況特殊處理)
參考:(模板特化)https://harttle.land/2015/10/03/cpp-template.html
(27) 成員初始化列表的概念慷垮,為什么用成員初始化列表會快一些
兩種方式:先構(gòu)造再復制(default構(gòu)造->copy assignment),拷貝構(gòu)造汤纸;操作次數(shù)不同蹲嚣,因此初始化成員列表更快祟牲。
補充:初始化列表順序為聲明順序说贝,且先基類后派生類。
參考:《effective C++》條款04
(28) 用過C11嗎,知道C11新特性嗎运杭?(有面試官建議熟悉C11)
1函卒、for(:)
2报嵌、auto推斷
3锚国、decltype int x= 3; decltype(x) y = x;
4、lambda函數(shù)(匿名函數(shù))[capture](para){body};
5绘沉、override和final
6车伞、nullptr
7、sizeof(A::member);
參考:
https://my.oschina.net/wangxuanyihaha/blog/183151
https://blog.csdn.net/FX677588/article/details/70157088
(29) C++的調(diào)用慣例(簡單一點C++函數(shù)調(diào)用的壓棧過程)
(30)C++的四種強制轉(zhuǎn)換
dynamic_cast:
有條件轉(zhuǎn)換沸枯,動態(tài)類型轉(zhuǎn)換,運行時類型安全檢查(轉(zhuǎn)換失敗返回NULL):
1哪轿、安全的基類和子類之間轉(zhuǎn)換窃诉。
2赤套、必須要有虛函數(shù)容握。
3、相同基類不同子類之間的交叉轉(zhuǎn)換塑猖。但結(jié)果是NULL谈跛。
const_cast:
指向常量的指針感憾、指向常量的引用去掉常量屬性阻桅。注意:對象為指針和引用。
1占遥、常量指針被轉(zhuǎn)化成非常量的指針瓦胎,并且仍然指向原來的對象;
2柬祠、常量引用被轉(zhuǎn)換成非常量的引用漫蛔,并且仍然指向原來的對象旧蛾;
3锨天、const_cast一般用于修改指針。如const char *p形式搂赋。
static_cast:
1脑奠、static_cast 作用和C語言風格強制轉(zhuǎn)換的效果基本一樣捺信,由于沒有運行時類型檢查來保證轉(zhuǎn)換的安全性欠痴,所以這類型的強制轉(zhuǎn)換和C語言風格的強制轉(zhuǎn)換都有安全隱患喇辽。
2菩咨、用于類層次結(jié)構(gòu)中基類(父類)和派生類(子類)之間指針或引用的轉(zhuǎn)換。注意:進行上行轉(zhuǎn)換(把派生類的指針或引用轉(zhuǎn)換成基類表示)是安全的特占;進行下行轉(zhuǎn)換(把基類指針或引用轉(zhuǎn)換成派生類表示)時是目,由于沒有動態(tài)類型檢查标捺,所以是不安全的。
3冤今、 用于基本數(shù)據(jù)類型之間的轉(zhuǎn)換茂缚,如把int轉(zhuǎn)換成char脚囊,把int轉(zhuǎn)換成enum凑术。這種轉(zhuǎn)換的安全性需要開發(fā)者來維護淮逊。
4扶踊、 static_cast不能轉(zhuǎn)換掉原有類型的const秧耗、volatile备籽、或者 __unaligned屬性。(前兩種可以使用const_cast 來去除)
5分井、在c++ primer 中說道:c++的任何的隱式轉(zhuǎn)換都是使用 static_cast 來實現(xiàn)车猬。
reinterpret_cast:
reinterpret_cast操作符代替了大多數(shù)其它C風格類型轉(zhuǎn)換的使用。reinterpret_cast將指針轉(zhuǎn)換為其它指針類型尺锚、將數(shù)字轉(zhuǎn)換為指針或?qū)⒅羔樲D(zhuǎn)換為數(shù)字珠闰。
參考:
https://blog.csdn.net/ydar95/article/details/69822540
https://www.cnblogs.com/balingybj/p/4771141.html
(31)STL源碼中的hash表的實現(xiàn)
存{key, value}:
1、BucketNum = func(hash(key))
2瘫辩、value放入Mem[BucketNum]
取{key, value}:
1伏嗜、BucketNum = func(hash(key))
2伐厌、在Mem[BucketNum]中查找value
參考:
https://blog.csdn.net/u010025211/article/details/46653519
(32) STL中unordered_map和map的區(qū)別
使用map情況:需要有序的數(shù)據(jù)承绸。
使用unordered_map:不要求數(shù)據(jù)的排序。
參考:
(unordered_map vs map) https://www.geeksforgeeks.org/map-vs-unordered_map-c/
(hash table vs BST) https://www.geeksforgeeks.org/advantages-of-bst-over-hash-table/
(33) STL中vector的實現(xiàn)
三指針:_Myfirst, _Mylast, _Myend
參考:https://blog.csdn.net/u012658346/article/details/50725933
(34) vector使用的注意點及其原因挣轨,頻繁對vector調(diào)用push_back()對性能的影響和原因军熏。
vector的capacity不夠用時,會重新分配內(nèi)存空間卷扮,并且將原來的數(shù)據(jù)復制到新的空間中羞迷,該過程開銷大界轩。
參考:https://blog.csdn.net/xi_niuniu/article/details/47060453
總參考:
(C++面試題整理)http://www.reibang.com/p/9aae0e5dc21a