針對算法方向或者應(yīng)屆畢業(yè)生對c++有需求咏花,但是要求不高的,如果資深c++算是十級的話阀趴,這篇文章的難度昏翰,僅僅將盡2-3級。
c++:
1:new刘急、delete棚菊、malloc、free關(guān)系叔汁?
a.屬性
new/delete是C++關(guān)鍵字统求,需要編譯器支持。malloc/free是庫函數(shù)据块,需要頭文件支持c码邻。
b.參數(shù)
使用new操作符申請內(nèi)存分配時無須指定內(nèi)存塊的大小,編譯器會根據(jù)類型信息自行計算瑰钮。而malloc則需要顯式地指出所需內(nèi)存的尺寸冒滩。
c.返回類型
new操作符內(nèi)存分配成功時,返回的是對象類型的指針浪谴,類型嚴格與對象匹配开睡,無須進行類型轉(zhuǎn)換,故new是符合類型安全性的操作符苟耻。而malloc內(nèi)存分配成功則是返回void * 篇恒,需要通過強制類型轉(zhuǎn)換將void*指針轉(zhuǎn)換成我們需要的類型。
e. 分配失敗
new內(nèi)存分配失敗時凶杖,會拋出bac_alloc異常胁艰。malloc分配內(nèi)存失敗時返回NULL。
f.自定義類型
???????? new會先調(diào)用operator new函數(shù),申請足夠的內(nèi)存(通常底層使用malloc實現(xiàn))腾么。然后調(diào)用類型的構(gòu)造函數(shù)奈梳,初始化成員變量,最后返回自定義類型指針解虱。delete先調(diào)用析構(gòu)函數(shù)攘须,然后調(diào)用operator delete函數(shù)釋放內(nèi)存(通常底層使用free實現(xiàn))。
???????? malloc/free是庫函數(shù)殴泰,只能動態(tài)的申請和釋放內(nèi)存于宙,無法強制要求其做自定義類型對象構(gòu)造和析構(gòu)工作。
2:多態(tài)?
為什么有多態(tài)悍汛?多態(tài)的意義捞魁?:這個就不用說了。
多態(tài)通過什么實現(xiàn)离咐?:虛函數(shù)谱俭。虛函數(shù)是指一個類中你希望重載的成員函數(shù) ,當你用一個 ?基類指針或引用? ?指向一個繼承類對象的時候健霹,調(diào)用一個虛函數(shù)時, 實際調(diào)用的是繼承類的版本旺上。
虛函數(shù)在實際項目中如何應(yīng)用糖埋?:父類指針指向子類的對象宣吱,當調(diào)用父類中的虛函數(shù)的時候,就會執(zhí)行子類的對應(yīng)方法瞳别。具體例子請看這里:https://www.cnblogs.com/weiyouqing/p/7544988.html
虛函數(shù)的原理征候?:要點是要答出虛函數(shù)表和虛函數(shù)表指針的作用
虛函數(shù)是用來實現(xiàn)動態(tài)綁定的。
C++中虛函數(shù)使用虛函數(shù)表和虛函數(shù)表指針實現(xiàn)祟敛,虛函數(shù)表是一個類的虛函數(shù)的地址表疤坝,用于索引類本身以及父類的虛函數(shù)的地址,假如子類重寫了父類的虛函數(shù)馆铁,則對應(yīng)在虛函數(shù)表中會把對應(yīng)的虛函數(shù)替換為子類的函數(shù)的地址(子類中可以不是虛函數(shù)跑揉,但是必須同名);虛函數(shù)表指針存在于每個對象中(通常出于效率考慮埠巨,會放在對象的開始地址處)历谍,它指向?qū)ο笏陬惖奶摵瘮?shù)表的地址;在多繼承環(huán)境下辣垒,會存在多個虛函數(shù)表指針望侈,分別指向?qū)?yīng)不同基類的虛函數(shù)表。
虛函數(shù)表是每個(有虛函數(shù)的)類對應(yīng)一個勋桶。虛函數(shù)表指針是每個對象對應(yīng)一個脱衙。
虛函數(shù)表里只能存放虛函數(shù)侥猬,不能存放普通函數(shù)。
如果一個函數(shù)不是虛函數(shù)捐韩,那么對它的調(diào)用(即該函數(shù)的地址)在編譯階段就會確定退唠。調(diào)用虛函數(shù)的話(它的地址)要運行時才能確定。
虛函數(shù)的函數(shù)入口是動態(tài)綁定的荤胁。在運行時铜邮,程序根據(jù)基類指針指向的實際對象,來調(diào)用該對象對應(yīng)版本的函數(shù)寨蹋。(用該對象的虛函數(shù)表指針找到其虛函數(shù)表,進而調(diào)用不同的函數(shù)扔茅。)(只有是虛函數(shù)的情況下才會這么做(用虛函數(shù)表指針去查虛函數(shù)表)已旧。非虛函數(shù)直接就調(diào)用自己的。
?為什么需要虛析構(gòu)函數(shù)召娜?(什么情況下要用虛析構(gòu)函數(shù)运褪?):
在存在類繼承并且析構(gòu)函數(shù)中需要析構(gòu)某些資源時,析構(gòu)函數(shù)需要是虛函數(shù)玖瘸。否則若使用父類指針指向子類對象秸讹,在delete時只會調(diào)用父類的析構(gòu)函數(shù),而不能調(diào)用子類的析構(gòu)函數(shù)雅倒,造成內(nèi)存泄露璃诀。
注:純虛函數(shù)寫法上就是比虛函數(shù)多寫 =0. 純虛函數(shù)是子類必須實現(xiàn)的。
以上就是虛函數(shù)部分蔑匣,這個深度應(yīng)該對應(yīng)屆畢業(yè)生 應(yīng)該足夠了劣欢,如果再深就有些變態(tài)了。
3 :種強制類型轉(zhuǎn)換操作符:static_cast裁良、dynamic_cast凿将、const_cast、reinterpret_cast
static_cast: 1)完成基礎(chǔ)數(shù)據(jù)類型价脾,2)同一個繼承體系中類型的轉(zhuǎn)換 3)任意類型與空指針類型void*之間的轉(zhuǎn)換牧抵。
dynamic_cast:使用多態(tài)的場景,增加了一層對真實調(diào)用對象類型的檢查侨把。
const_cast去除指針或引用的const屬性犀变。
1、轉(zhuǎn)化常量指針為非常量的指針座硕,并且仍然指向原來的對象弛作;?
2、轉(zhuǎn)化常量引用為非常量的引用华匾,并且仍然指向原來的對象映琳;?
3机隙、const_cast一般用于修改指針。如const int *ptr形式萨西。
reinterpret_cast:進行無關(guān)類型的轉(zhuǎn)換(不必做過多了解)
使用場景:https://www.cnblogs.com/zeppelin5/p/10075569.html
4:C++內(nèi)存對齊
1有鹿、第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)成員的對齊按照#pragma pack指定的數(shù)值和這個數(shù)據(jù)成員自身長度中谎脯,比較小的那個進行葱跋。
2、在數(shù)據(jù)成員完成各自對齊之后源梭,類(結(jié)構(gòu)或聯(lián)合)本身也要進行對齊娱俺,對齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長度中,比較小的那個進行废麻。
不懂得 自行百度荠卷,這個問題 很少面試會問,都是做筆試題烛愧,可能會有油宜。
5:如何解決類之間的相互依賴問題?
在實際寫代碼時經(jīng)常會碰到 class A 中用到class B 而class B中也用到了class A怜姿,這種情況下就會報錯慎冤,某個方法不是類中的member。
這種情況下沧卢,?此種狀況的解決利用前置聲明定義的那個類中的保持另外一個類的引用定義為指針蚁堤,定義指針時不需要對那個類的定義可見。注意 頭文件中利用前置聲明但狭,這樣的話一定不能寫定義违寿,定義一定要在cpp中實現(xiàn),這個cpp中#include class A的頭文件熟空。
https://www.csdn.net/gather_22/Ntjagg4sMTYtYmxvZwO0O0OO0O0O.html
6:如何解決頭文件的循環(huán)引用問題藤巢?
為了防止兩次include同一個頭文件 ,這個問題涉及到一個寫代碼的習慣問題息罗,寫頭文件時一定要加#ifndef這一套掂咒。
7:智能指針的種類和原理:
8:多線程之間的通信:
9:你所了解的c++常見的標準庫
10:設(shè)計模式
如何寫一個線程安全的單例模式?
單例模式不用過多贅述迈喉,就是一個項目中绍刮,只存在一個這個類的對象,實現(xiàn)的原理就是將這個類的構(gòu)造函數(shù)設(shè)為private挨摸,對外只提供一個static的GetInstance的接口獲取這個類的靜態(tài)對象孩革,當然這個靜態(tài)對象也是private的,需要注意的是得运,在實現(xiàn)文件中膝蜈,一定要將這個靜態(tài)unique_instance初始化為NULL锅移,因為靜態(tài)變量 一定要初始化。下面說一下線程安全的單例模式
懶漢模式:
template classsingleton{
protected:
singleton(){};
private:
? ? singleton(constsingleton&){};
? ? singleton&operator=(constsingleton&){};
? ? staticT* m_instance;public:
? ? staticT* GetInstance();
};
template T* singleton::GetInstance()
{
? ? if( m_instance == NULL)
? ? {
? ? ? ? m_instance =new T();
? ? }
? ? return m_instance;
}
template T* singleton::m_instance = NULL;
????在定義m_instance變量時先等于NULL饱搏,在調(diào)用GetInstance()方法時非剃,在判斷是否要賦值。這種模式推沸,并非是線程安全的备绽,因為多個線程同時調(diào)用GetInstance()方法,就可能導(dǎo)致有產(chǎn)生多個實例鬓催。要實現(xiàn)線程安全肺素,就必須加鎖。? ??
template classsingleton{
protected:
singleton(){};
private:
? ? singleton(constsingleton&){};
? ? singleton&operator=(constsingleton&){};
? ? staticT* m_instance;
? ? static pthread_mutex_t mutex;public:
? ? staticT* GetInstance();
};
template <class T>T* singleton<T>::GetInstance()
{
? ? if( m_instance == NULL)
? ? {
? ? ? ? pthread_mutex_lock(&mutex);
if( m_instance == NULL)
? ? ? ? {
? ? ? ? ? ? T* ptmp =new T();
? ? ? ? ? ? m_instance = ptmp;
? ? ? ? }
? ? ? ? pthread_mutex_unlock(&mutex);
? ? }
? ? return m_instance;
}
template pthread_mutex_t singleton::mutex = PTHREAD_MUTEX_INITIALIZER;
template T* singleton::m_instance = NULL;