cpp技術(shù)知識點筆記:
1:list 和 vector的實現(xiàn)區(qū)別?
list空間按需分配,是鏈表類型,內(nèi)存不一定連續(xù),在插入和刪除的時候不會引起迭代器失效,刪除元素只有當(dāng)前元素的迭代器失效
vector的空間是連續(xù)的,空間不足的情況下,(1)開辟新的大內(nèi)存空間;(2)從舊的空間拷貝數(shù)據(jù)到新的內(nèi)存空間;(3)釋放舊的空間
vector的內(nèi)部空間,總是供大于需,避免頻繁的數(shù)據(jù)移動操作,size = 2*size 插入和刪除可能引起迭代器失效。
vector的刪除操作引起迭代器失效:刪除可能導(dǎo)致某個迭代器訪問不再合法、然后繼續(xù)訪問就有可能訪問已經(jīng)失效的空間。
2:指針和引用?
指針有空間,存儲的是一個地址。引用只是變量別名。
指針可以為NULL,引用不可以為空。
指針可以在初始化之后,改變指向,引用一旦初始化將不能改變。
存在const修飾的指針,不可以改變指向,不存在const修飾的引用。
指針可以有二級操作,**p 引用沒有。
指針指向的變量,需要解引用,引用直接訪問就行。
指針和引用自增的含義不同。
3:define和const區(qū)別?
define定義的是一個字符串,沒有類型,沒有存儲器,編譯器不對其進行安全檢查,const有類型,存在數(shù)據(jù)段,可以進行安全檢查。
define不可以調(diào)試,const可以調(diào)試。
define在預(yù)處理時進行替換,const在編譯時進行。
4:char arr[10]; 和 char *p = new char[10] 區(qū)別?
char arr[10]; 字符數(shù)組未初始化 ,存放在未初始化的的數(shù)據(jù)區(qū),如果存在static修飾,則存放在靜態(tài)數(shù)據(jù)區(qū)。
new char[10]; 定義的字符數(shù)組,使用'/0'進行初始化,存放在堆中。
5:c++的內(nèi)存分配方式?內(nèi)存分布圖?
new、malloc分配空間,需要手動釋放。
系統(tǒng)在棧上分配空間,函數(shù)調(diào)用的參數(shù)信息,系統(tǒng)釋放。
static靜態(tài)存儲分配空間。
? ? ? ? 棧
? ? ? ? 堆
? ? 未初始化數(shù)據(jù)段
? ? 初始化數(shù)據(jù)段
? ? ? 代碼段
6:自實現(xiàn)String類:?
class String
{
? ? public:
? ? ? ? String(const char *str);
? ? ? ? String(const String &other);
? ? ? ? String& operator=(const String &other);
? ? ? ? ~String();
? ? private:
? ? ? ? m_data;
? ? ? ? m_size;
}
String::String(const char* str)
{
? ? if(str == nullptr)
? ? {
? ? ? ? m_data = new char[1];
? ? ? ? m_data[0] = '\0';
? ? ? ? m_size = 0;
? ? }
? ? else
? ? {
? ? ? ? m_size = strlen(str);
? ? ? ? m_data = new char[m_size + 1];
? ? ? ? strcpy(m_data, str);
? ? }
}
String::String(const String& other)
{
? ? m_size = other.m_size;
? ? m_data = new char[m_size + 1];
? ? strcpy(m_data, other.m_data);
}
String::String& operator=(const String& other)
{
? ? if(this == &other)
? ? {
? ? ? ? return *this;
? ? }
? ? delete[] m_data;
? ? m_size = strlen(other.m_data);
? ? m_data = new char[m_size + 1];
? ? strcpy(m_data, other.m_data);
? ? return *this;
}
7:extern關(guān)鍵字?
置于變量或者函數(shù)前,表示變量或者函數(shù)定義在別的文件中。
extern 和 C連用的時候,告訴編譯器編譯時候用c的方式編譯。
當(dāng)不與c連用的時候,作用聲明函數(shù)或者全局變量的作用范圍。
8:static關(guān)鍵字?
? 1.修飾局部變量:存放在靜態(tài)變量區(qū),聲明周期和main函數(shù)相同,main函數(shù)之前初始化,函數(shù)結(jié)束退出。
? 2.修飾全局變量:全局變量原本就存放在靜態(tài)區(qū),static修飾,使其只能被包含該定義的文件訪問,修改了其作用域。
? 3.修飾函數(shù):static修飾的函數(shù),只能在包含改定義的文件中調(diào)用,靜態(tài)函數(shù),聲明和定義需要在同一個文件中。
? 4.修飾成員變量:使其成為類的全局變量,所有類對象共享,包括派生類,只能在類外進行初始化。可以使用const修飾在類內(nèi)進行初始化。
? ? 靜態(tài)數(shù)據(jù)成員,實體遠(yuǎn)在main函數(shù)開始前已經(jīng)在全局?jǐn)?shù)據(jù)段中誕生了。生命周期和類對象是異步的。這個時候類對象還沒有開始,但是靜態(tài)數(shù)據(jù)成員已經(jīng)可以訪問了。為了此所以一定要在類外初始化。
? 5.成員函數(shù):只存在一份該函數(shù),所有對象共享,不含this指針,無需創(chuàng)建任何對象就可以訪問。
? 不可以同時使用const和static修飾成員函數(shù),原因c++在實現(xiàn)const修飾的函數(shù)時候,會在函數(shù)中隱式添加一個const this*,static是沒有this指針的,互相矛盾。
9:volatile作用?
修飾變量,表名某個變量隨時可能會被外部改變,改變量不能被緩存到寄存器,每次需要重新讀取。
10:const的作用?
? 1.修飾變量,只讀變量,不可以被更改。
? 2.修飾函數(shù)參數(shù)(返回值,一般很少用),參數(shù)內(nèi)容不能被修改
? 3.修飾指針,指針?biāo)笇ο蟛荒鼙桓淖?。int* const p = &a; 指針p指向a的地址,不能再被改變。
? 4.修飾指針?biāo)傅淖兞?,int const *p = &a; const修飾*p, *p所指的內(nèi)容不能被改變。
? 5.修飾類成員函數(shù),表明是一個常函數(shù),不能修改類的成員變量。
? 一個成員函數(shù)不會修改成員值,最好將其修飾為const函數(shù),void func() const;
11: new和malloc?
malloc和free是C語言的標(biāo)準(zhǔn)庫函數(shù),new和delete是c++的運算符,都可以進行申請內(nèi)存和釋放內(nèi)存。
對于非內(nèi)部數(shù)據(jù)結(jié)構(gòu)的類型而言,malloc和free無法滿足動態(tài)對象要求。
new可以認(rèn)為是malloc加構(gòu)造函數(shù)的執(zhí)行,new出來的指針是直接帶構(gòu)造信息的,malloc返回的都是void指針。
12:c++多態(tài)?
一個接口,多種方法,c++多態(tài)主要通過虛函數(shù)實現(xiàn)的,虛函數(shù)允許子類從寫overrid。
編譯時多態(tài):通過重載函數(shù)實現(xiàn)。
運行時多態(tài):通過虛函數(shù)實現(xiàn)。
13: c++的虛函數(shù) 純虛函數(shù)?
純虛函數(shù)是在基類中聲明的虛函數(shù),基類中沒有定義,函數(shù)原型后加=0,純虛函數(shù)的實現(xiàn)起到規(guī)范作用,繼承的類必須按照這個形式自己實現(xiàn)。
虛函數(shù),運行時多態(tài),父類提供虛函數(shù)實現(xiàn),子類可以重寫父類虛函數(shù)實現(xiàn)子類的特殊化。
c++包含純虛函數(shù)的類是抽象類,抽象類不能new出對象。只有實現(xiàn)了純虛函數(shù)的子類,才可以。
14: 靜態(tài)綁定和動態(tài)綁定?
靜態(tài)綁定發(fā)生在編譯期,動態(tài)綁定發(fā)生在運行期。
動態(tài)類型可以更改,靜態(tài)類型不可以更改。
繼承體系中,只有虛函數(shù)使用的是動態(tài)綁定,其它使用的都是靜態(tài)綁定。
靜態(tài)多態(tài)使用的是模板技術(shù),或者是函數(shù)重載技術(shù)。動態(tài)多態(tài)通過虛函數(shù)實現(xiàn)在運行期綁定的技術(shù)。
15:值傳遞和引用傳遞?
值傳遞是指當(dāng)函數(shù)發(fā)生函數(shù)調(diào)用時候,給形參分配空間,用實參來初始化形參,這一過程是參數(shù)值得單項傳遞。形參不影響實參。
引用傳遞,將引用作為形參,系統(tǒng)初始化時,自動使用實參來初始化形參,形參是實參的一個別名,直接操作的是實參。
16: 內(nèi)聯(lián)函數(shù)?特點?
將inline放在函數(shù)聲明前不起任何作用,必須要放在定義函數(shù)前。
使用關(guān)鍵字inline的函數(shù),編譯器在調(diào)用處,使用函數(shù)體進行替換,節(jié)省參數(shù)傳遞,控制轉(zhuǎn)移開銷。
內(nèi)聯(lián)函數(shù)不能有循環(huán),和switch語句;
內(nèi)聯(lián)函數(shù)定義,必須出現(xiàn)在第一次調(diào)用之前;不能有異常聲明。
17: 拷貝構(gòu)造函數(shù)和 operator=?
前者屬于構(gòu)造函數(shù),后者屬于運算符重載。
對于在賦值操作之前,還沒有構(gòu)造的變量,調(diào)用拷貝構(gòu)造函數(shù)。
賦值之前,已經(jīng)構(gòu)造的變量,調(diào)用賦值操作。
class_obj a("xxx"); class_obj b = a; //拷貝構(gòu)造 class_obj c; c = a; // 賦值operator=
18: 友元函數(shù)?
friend修飾,不可以繼承,不可以傳遞,可以訪問相應(yīng)類的公有,私有,受保護的成員。
19: 抽象類?
帶有純虛函數(shù)的類叫抽象類。
純虛函數(shù):基類中僅僅給出聲明,不對虛函數(shù)實現(xiàn)定義,而是在派生類中實現(xiàn),該函數(shù)成為純虛函數(shù)。
抽象類的析構(gòu)函數(shù)應(yīng)被聲明為virtaul,因為涉及到繼承。
20: 虛構(gòu)造函數(shù)?虛析構(gòu)函數(shù)?
不能聲明虛構(gòu)造函數(shù),多態(tài)是不同對象對同一消息的不同特性,虛函數(shù)作為運行多態(tài)的基礎(chǔ),主要針對對象,構(gòu)造函數(shù)是在對象生成之前運行的,沒有意義。
可以聲明為虛析構(gòu)函數(shù),析構(gòu)函數(shù)是對象釋放的一些清理工作,一個類的析構(gòu)函數(shù)是虛函數(shù),由它派生而來的所有子類也是虛函數(shù),析構(gòu)函數(shù)設(shè)置為虛函數(shù),就可以
調(diào)用適當(dāng)?shù)奈鰳?gòu)函數(shù)對不同的對象進行清理工作。
21: 函數(shù)重載和函數(shù)重寫?
重載:同名不同參的函數(shù),互相被稱為重載函數(shù)。
? ? 條件:1.名必須相同,2.參數(shù)必須不同,3.返回值都可。
重寫:也可叫覆蓋,繼承中,子類重新定義父類中有相同名稱和參數(shù)的虛函數(shù)。
? ? 條件:1.兩個函數(shù)都必須是虛函數(shù),一個在基類,一個在派生類。2.函數(shù)名和參數(shù)必須一致。3.返回值相同。
22: class和struct?
默認(rèn)成員訪問權(quán)限不同,struct是公有訪問,class是私有訪問。
默認(rèn)繼承方式不同,struct是公有繼承, class是私有繼承。
定義模板時可以使用class,不能使用struct。
都可以包含成員函數(shù),實現(xiàn)繼承,都可以實現(xiàn)多態(tài)。
23: 淺拷貝和深拷貝?
對一個對象進行拷貝,默認(rèn)是復(fù)制構(gòu)造拷貝,兩個對象的指針成員所指內(nèi)存相同。只對指針進行拷貝。
編譯器在我們沒有定義拷貝構(gòu)造函數(shù)時候,采用默認(rèn)拷貝構(gòu)造函數(shù),進行淺拷貝,兩個指針指向同一個內(nèi)存空間。
深拷貝不但對指針進行拷貝,而且對指針?biāo)竷?nèi)容也進行了拷貝,深拷貝的內(nèi)容兩份,淺拷貝內(nèi)容一份。
24: 析構(gòu)函數(shù)帶virtual?
基類派生,析構(gòu)函數(shù)一定要帶virtaul關(guān)鍵字,基類指針指向派生類對象,刪除該指針時,并不會釋放派生類對象的空間,不會調(diào)用派生類析構(gòu)函數(shù)。
不需要基類指針指向派生類對象,可以不用帶virtaul。
25: delete 和 delete[]?
delete釋放內(nèi)存,delete ptr釋放ptr指向的內(nèi)存。
delete[] 釋放內(nèi)存,逐一調(diào)用數(shù)組的每個對象的析構(gòu)函數(shù),全部釋放。
26: 顯示轉(zhuǎn)換?
static_cast: 基本類型之間的數(shù)據(jù)轉(zhuǎn)換。
const_cast: 將const類型的指針轉(zhuǎn)換為非const類型的指針。
reinterpret_cast: 不相關(guān)類型之間的轉(zhuǎn)化,目標(biāo)和原始之間有相同的位數(shù)。
dynamic_cast: 運行時檢查轉(zhuǎn)換是否安全,用于類層次間的上行和下行轉(zhuǎn)化。
27: 運算符重載?
實際上是函數(shù)重載,改變運算符的操作方式,使其可以適用類類型,為類提供一個接口,使語言面向問題而不是面向程序。
增強c++的擴展性。
28: stl?
c++提供的標(biāo)準(zhǔn)模板庫。
組成:容器,迭代器,算法,函數(shù)對象適配器。算法位于核心。
29: auto?
const 和 volatile c++的兩種屬性
聲明為auto的變量不能從初始表達(dá)式中帶走cv(上面那兩種)限制符
const int a = 1; auto b = a; // b int類型? auto &c = a; // c是const int類型
decltype則可以帶走cv限制符。
但是,如果是一個對象的定義中含有const或volatile限制符,使用decltype進行推導(dǎo)時候,其成員不會繼承cv的限制。
30: 預(yù)處理->編譯->匯編->鏈接?
1 預(yù)編譯 過程主要處理那些源文件中的以“#”開始的預(yù)編譯指令,主要處理規(guī)則有:
? ? 1.將所有的“#define”刪除,并展開所用的宏定義
? ? 2.處理所有條件預(yù)編譯指令,比如“#if”、“#ifdef”、 “#elif”、“#endif”
? ? 3.處理“#include”預(yù)編譯指令,將被包含的文件插入到該編譯指令的位置,注:此過程是遞歸進行的
? ? 4.刪除所有注釋
? ? 5.添加行號和文件名標(biāo)識,以便于編譯時編譯器產(chǎn)生調(diào)試用的行號信息以及用于編譯時產(chǎn)生編譯錯誤或警告時可顯示行號
? ? 6.保留所有的#pragma編譯器指令。
2 編譯 過程就是把預(yù)處理完的文件進行一系列的詞法分析、語法分析、語義分析及優(yōu)化后生成相應(yīng)的匯編代碼文件。這個過程是整個程序構(gòu)建的核心部分
3 匯編 器是將匯編代碼轉(zhuǎn)化成機器可以執(zhí)行的指令,每一條匯編語句幾乎都是一條機器指令。經(jīng)過編譯、鏈接、匯編輸出的文件成為目標(biāo)文件。
4 鏈接 的主要內(nèi)容就是把各個模塊之間相互引用的部分處理好,使各個模塊可以正確的拼接。 鏈接的主要過程包塊 地址和空間的分配、符號決議和重定位等步驟。
31: 靜態(tài)鏈接和動態(tài)鏈接?
靜態(tài):靜態(tài)鏈接的時候,載入代碼就會把程序會用到的動態(tài)代碼或動態(tài)代碼的地址確定下來。
動態(tài):直到真正調(diào)用動態(tài)庫代碼時,載入程序才計算(被調(diào)用的那部分)動態(tài)代碼的邏輯地址,但運行期間的性能比不上靜態(tài)鏈接的程序。
32: 構(gòu)造函數(shù)存在自動轉(zhuǎn)換功能:
聲明構(gòu)造函數(shù)的時候前面添加上explicit即可,這樣就可以防止這種自動的轉(zhuǎn)換操作。
33: 關(guān)鍵字registr,typdef的作用?
regist盡可能讓變量保存在cpu的寄存器中,減去cpu從內(nèi)存抓取效率,提高運行效率。
注意:
? ? 局部變量才可以被修飾register
? ? 不能取地址,地址存放在內(nèi)存,但是它在寄存器。
? ? 一定是cpu所接受的類型。
typedef:起一個新名字。
? ? 提高移植性。
? ? 提高編碼效率。
? ? 解釋數(shù)據(jù)類型作用。
34:explicit關(guān)鍵字的作用?
編譯器有記憶功能,為的是將頻繁使用到的變量,保存在寄存器中,提高效率。
但是如果該變量在內(nèi)存中被改動了,寄存器中的值就不再有效,但是計算器不知道,還是會使用寄存器中的值。
解決此辦法就是加上關(guān)鍵字explicit關(guān)鍵字,提醒cpu每次從內(nèi)存中取改值。