1刷袍、inline 關(guān)鍵字
- 使用內(nèi)聯(lián)函數(shù)可以節(jié)省運(yùn)行時(shí)間米碰,因?yàn)榫幾g的時(shí)候,內(nèi)聯(lián)函數(shù)相當(dāng)于直接把代碼copy到調(diào)用處堡掏,可以節(jié)省函數(shù)調(diào)用的堆棧開(kāi)銷应结。
- 一般只將規(guī)模很小,使用頻繁的函數(shù)生命為內(nèi)聯(lián)函數(shù)泉唁,從代碼整潔角度來(lái)說(shuō)摊趾,這是很合理的(但是真正的原因是币狠?)。
- 內(nèi)聯(lián)函數(shù)不能包含復(fù)雜的控制語(yǔ)句砾层。
- 類的成員函數(shù)也可以指定為內(nèi)聯(lián)函數(shù)漩绵。
2、 通過(guò)引用變量訪問(wèn)對(duì)象中的成員
- 引用變量相當(dāng)于為一個(gè)變量起別名肛炮,有時(shí)候他的功效和指針很像止吐,底層是怎么實(shí)現(xiàn)的有待探討。
3侨糟、構(gòu)造函數(shù)的規(guī)則
- 構(gòu)造函數(shù)不需要用戶調(diào)用碍扔,而是在建立對(duì)象時(shí)候自動(dòng)調(diào)用(注意,這個(gè)在對(duì)象沒(méi)有初始值的時(shí)候秕重,是不會(huì)調(diào)用的不同,這個(gè)說(shuō)話有誤。)
- 構(gòu)造函數(shù)的名字必須和類名字相同溶耘,而不能有用戶任意命名
- 構(gòu)造函數(shù)不具有任何類型二拐,不返回任何值
- 構(gòu)造函數(shù)的功能有用戶定義的,用戶根據(jù)初始化的要求設(shè)計(jì)函數(shù)體和函數(shù)參數(shù)
- 帶默認(rèn)參數(shù)的構(gòu)造函數(shù)凳兵,會(huì)和默認(rèn)構(gòu)造函數(shù)產(chǎn)生歧義百新,比如 student(); 和 student(int age = 0); 會(huì)導(dǎo)致編譯錯(cuò)誤。 正確的寫(xiě)法為
正確的寫(xiě)法:
student();
student(int); // 不帶默認(rèn)參數(shù)
4庐扫、關(guān)于釋構(gòu)函數(shù)的注意點(diǎn)
- 釋構(gòu)函數(shù)不返回任何值饭望,沒(méi)有函數(shù)類型,也沒(méi)有函數(shù)參數(shù)
- 釋構(gòu)函數(shù)不能被重載形庭,一個(gè)類可以有多個(gè)構(gòu)造函數(shù)铅辞,但是只能有一個(gè)釋構(gòu)函數(shù)
- 釋構(gòu)函數(shù)的作用并不僅限于釋放資源,它還可以被用來(lái)執(zhí)行”用戶希望在最后一次使用對(duì)象之后所執(zhí)行的任何操作“
- 如果用戶沒(méi)有定義釋構(gòu)函數(shù)萨醒,C++編譯系統(tǒng)會(huì)自動(dòng)生成一個(gè)釋構(gòu)函數(shù)
5斟珊、const關(guān)鍵字的作用
常對(duì)象
用const修飾的對(duì)象,里面的所有成員變量不能被修改
凡是希望數(shù)據(jù)成員不被修改的對(duì)象验靡,都可以聲明為常對(duì)象倍宾,聲明方法: const object(0) 或者 object const(0);
常對(duì)象成員變量必須有初始值雏节,否則編譯報(bào)錯(cuò)胜嗓。
指向?qū)ο蟮某V羔?/h3>
將指針變量聲明為const類型,其指針的值不能改變
一般定義方式為 object * const abc;
object a(0) , b(0) ; object * const pt = &a; pt = &b; //錯(cuò)誤
指向常變量的指針變量
const object * a / object const * a;
如果一個(gè)變量已被聲明為常變量/對(duì)象钩乍,只能用指向常變量/對(duì)象的指針指向它辞州,而不能用指向非
指向常變量的指針變量可以指向未被聲明為const的變量,但不能通過(guò)此指針變量改變?cè)撟兞康闹怠?/p>
指向常對(duì)象的指針最常用于函數(shù)的形參寥粹,以保護(hù)形參指針?biāo)赶虻膶?duì)象在函數(shù)執(zhí)行過(guò)程中不被修改变过。
void doSomething1(const Test *p1)
{
p1->setX(5); //非法埃元!
p1->printxy( );
}
將指針變量聲明為const類型,其指針的值不能改變
一般定義方式為 object * const abc;
object a(0) , b(0) ; object * const pt = &a; pt = &b; //錯(cuò)誤
const object * a / object const * a;
如果一個(gè)變量已被聲明為常變量/對(duì)象钩乍,只能用指向常變量/對(duì)象的指針指向它辞州,而不能用指向非
指向常變量的指針變量可以指向未被聲明為const的變量,但不能通過(guò)此指針變量改變?cè)撟兞康闹怠?/p>
指向常對(duì)象的指針最常用于函數(shù)的形參寥粹,以保護(hù)形參指針?biāo)赶虻膶?duì)象在函數(shù)執(zhí)行過(guò)程中不被修改变过。
void doSomething1(const Test *p1)
{
p1->setX(5); //非法埃元!
p1->printxy( );
}
| 數(shù)據(jù)成員 | 非const成員函數(shù) | const 成員函數(shù) |
| --- | --- || --- |
| 非const數(shù)據(jù)成員 | 可引用,可改變值 | 可引用媚狰,不可改變值
| const數(shù)據(jù)成員 | 可引用岛杀,不可改變值 | 可引用,不可改變值
| const對(duì)象數(shù)據(jù)成員 | 不可引用崭孤,不可改變值 | 不可引用类嗤,不可改變值
6、對(duì)象的賦值和復(fù)制
- 同類對(duì)象之前可以互相賦值
- 對(duì)象賦值的一般形式為 obj1 = obj2
- 對(duì)象賦值的實(shí)現(xiàn)原理是賦值運(yùn)算符的重載
7辨宠、對(duì)象的復(fù)制
- 用已有的對(duì)象克隆出一個(gè)新對(duì)象
- 其一般形式為 類名 對(duì)象2(對(duì)象1);
- 原理是編譯系統(tǒng)提供默認(rèn)復(fù)制構(gòu)造函數(shù)
- C++的所有類型都實(shí)現(xiàn)了復(fù)制構(gòu)造函數(shù)遗锣,基本類型也是,比如 int a(5)嗤形,調(diào)用int的賦值構(gòu)造函數(shù)精偿,把參數(shù)5傳入生成一個(gè)int 類型。
- 當(dāng)函數(shù)參數(shù)為類對(duì)象的時(shí)候赋兵,調(diào)用函數(shù)時(shí)笔咽,實(shí)參賦值給形參會(huì)調(diào)用對(duì)象的復(fù)制構(gòu)造函來(lái)生成一個(gè)實(shí)參的拷貝
- 當(dāng)函數(shù)返回值為對(duì)象時(shí),在函數(shù)調(diào)用完畢毡惜,會(huì)復(fù)制一個(gè)對(duì)象返回給調(diào)用處
復(fù)制構(gòu)造函數(shù):
Object::Object(const Object& b){
a = b.a
}
8拓轻、友元
友元函數(shù)
- 如果在本類以外其他地方定義的函數(shù),在類體中用friend進(jìn)行聲明经伙,此函數(shù)成為本類的友元函數(shù)扶叉,該函數(shù)可以訪問(wèn)類的私有成員變量。
- 友元函數(shù)可以屬于不是任何類的非成員函數(shù)帕膜,也可以是其他類的成員函數(shù)枣氧。
- 一個(gè)函數(shù)(普通函數(shù)和成員函數(shù))可以聲明為多個(gè)類的友元函數(shù),這樣就可以訪問(wèn)多個(gè)類的私有數(shù)據(jù)垮刹。
友元類
- 如何一個(gè)類中聲明了其他類為友元類达吞,那么其他類就可以隨意反問(wèn)這個(gè)類的私有數(shù)據(jù)。
- 一般情況下不需要用到友元類荒典,雖然友元類有助于數(shù)據(jù)共享酪劫,但是嚴(yán)重影響了類的封裝性,不利于信息隱藏寺董,大多數(shù)問(wèn)題用友元函數(shù)就能解決覆糟。
9、運(yùn)算符重載
運(yùn)算符重載的意義
- 通過(guò)運(yùn)算符重載遮咖,擴(kuò)大C++已有運(yùn)算符的作用滩字,使用運(yùn)算符可以作用于類
- 使用運(yùn)算符重載技術(shù),能使程序易于編寫(xiě),閱讀和維護(hù)
- 運(yùn)算符被重載后麦箍,其原有的功能依然保留漓藕,沒(méi)有喪失或改變
- 運(yùn)算符重載實(shí)質(zhì)是函數(shù)的重載
運(yùn)算符重載的實(shí)現(xiàn)方法
對(duì)象+法運(yùn)算符重載
成員函數(shù)實(shí)現(xiàn)
// 寫(xiě)法一
object object::operator+(object & obj2){
object obj3;
obj3.a = obj2.a;
return obj3;
}
// 寫(xiě)法二
object object::operator+(object & obj2){
// 直接調(diào)用構(gòu)造函數(shù)返回
return object(obj2.a);
}
非成員函數(shù)實(shí)現(xiàn)方案
object operator+(object & obj1, object & obj2){
// 直接調(diào)用構(gòu)造函數(shù)返回
return object(obj1.a + obj2.a);
}
運(yùn)算符重載的規(guī)則
- 不允許創(chuàng)造新的運(yùn)算符,只能對(duì)已有C++的運(yùn)算符進(jìn)行重載
- C++ 不允許的重載運(yùn)算符有5個(gè)分別是:
成員運(yùn)算符.
成員指針訪問(wèn)運(yùn)算符.*
作用域運(yùn)算符::
sizeof
條件運(yùn)算符?:
- 重載不能改變運(yùn)算符運(yùn)算對(duì)象(就是不能改變運(yùn)算符的操作數(shù))
- 重載不能改變運(yùn)算符的優(yōu)先級(jí)
- 重載不能改變運(yùn)算符的結(jié)合性
- 重載的運(yùn)算符的函數(shù)不能帶有默認(rèn)參數(shù)
- 重載的運(yùn)算符必需和用戶定義的自定義類型對(duì)象一起使用挟裂,參數(shù)至少有一個(gè)是類對(duì)象或其引用
10享钞、類(繼承類)訪問(wèn)權(quán)限
- 訪問(wèn)權(quán)限不影響類的內(nèi)存布局
- struct 成員變量和繼承方式默認(rèn)都是public
- class 成員變量和繼承方式默認(rèn)都是private
- 如果成員變量和繼承方式同時(shí)都有訪問(wèn)權(quán)限限制,則遵從最小訪問(wèn)權(quán)限原則诀蓉,比如類繼承是protected,但是成員變量是private嫩与,那么最終這個(gè)成員變量的權(quán)限還是private
| * |public | protected | private |
| --- | --- || --- | --- |
| 同一個(gè)類 | YES | YES | YES |
| 派生類 | YES | YES | NO |
| 外部類 | YES | NO | NO |
11、匿名函數(shù)——lambda表達(dá)式
- 聲明Lambda 表達(dá)式
[capture list] (params list) mutable exception -> return type { function body}
各項(xiàng)具體含義
1. capture list 捕獲外部變量列表
2. params list 形參列表
3. mutable 指示符交排,用于說(shuō)明是否可以修改捕獲的變量
4. exception 異常設(shè)定
5. return type 返回類型
6. function body 函數(shù)體
// 實(shí)例
int a0 = 1;
int b0 = 2;
auto funcs = [=, &b0](int c)->int {return b0 += a0 + c;};
int ress = funcs(6);
12划滋、命名空間
- 為了解決C++標(biāo)準(zhǔn)庫(kù)中的標(biāo)識(shí)符與程序 中的全局標(biāo)識(shí)符之間以及不同庫(kù)中的 標(biāo)識(shí)符之間的同名沖突,標(biāo)準(zhǔn)C++庫(kù)的 所有的標(biāo)識(shí)符都定義在一個(gè)名為std的 命名空間中埃篓。
- C++有一個(gè)默認(rèn)的命名空間处坪,為全局命名空間為::
- 命名空間是ANSI C++引入的可以由用戶命名的作用域,用來(lái)處理程序中常見(jiàn)的同名沖突架专。
- 同名字的命名空間會(huì)在編譯過(guò)程中進(jìn)行合并
13同窘、有繼承關(guān)系的構(gòu)造函數(shù)調(diào)用
- 子類會(huì)默認(rèn)調(diào)用父類的無(wú)參構(gòu)造函數(shù)
- 如果子類的構(gòu)造函數(shù)顯示地調(diào)用了父類的有參構(gòu)造函數(shù),就不會(huì)再去調(diào)用默認(rèn)構(gòu)造函數(shù)
- 如果父類缺少無(wú)參構(gòu)造函數(shù)部脚,子類的構(gòu)造函數(shù)必須顯示地調(diào)用父類的有參構(gòu)造函數(shù)
14想邦、多態(tài)
靜態(tài)多態(tài)
- 函數(shù)重載和運(yùn)算符重載實(shí)現(xiàn)的多態(tài)性屬于靜態(tài)多態(tài)性
- 在程序編譯時(shí)系統(tǒng)就能決定調(diào)用的是哪個(gè)函數(shù),因此委刘,又稱編譯時(shí)的多態(tài)性
- 靜態(tài)多態(tài)性是通過(guò)函數(shù)的重載實(shí)現(xiàn)的(運(yùn)算符重載實(shí)質(zhì)上也是函數(shù)重載)
動(dòng)態(tài)多態(tài)
動(dòng)態(tài)多態(tài)性是在程序運(yùn)行過(guò)程中才動(dòng)態(tài)地確定操作所針對(duì)的對(duì)象丧没,動(dòng)態(tài)多態(tài)性又稱運(yùn)行時(shí)的多態(tài)性
- C++默認(rèn)沒(méi)有實(shí)現(xiàn)動(dòng)態(tài)多態(tài),只會(huì)根據(jù)指針類型去調(diào)用對(duì)應(yīng)的函數(shù)锡移。
- C++的動(dòng)態(tài)多態(tài)通過(guò)virtual 函數(shù)來(lái)實(shí)現(xiàn)
- 如果父類的函數(shù)是虛函數(shù)呕童,子類重寫(xiě)該函數(shù)也是虛函數(shù)
- 調(diào)用new object 和 new object() 是有區(qū)別的,后者會(huì)把成員變量初始化為0淆珊。
15夺饲、C++類型轉(zhuǎn)換
- 在C++中某些標(biāo)準(zhǔn)類型的數(shù)據(jù)之間可以自動(dòng)轉(zhuǎn)換
- 隱式類型轉(zhuǎn)換由C++編譯系統(tǒng)自動(dòng)完成的,用戶不需要干預(yù)
int i = 6;
i = 7.5 + i;
- 強(qiáng)制(顯式)類型轉(zhuǎn)換是指在程序中將一中類型數(shù)據(jù)明確轉(zhuǎn)換成另一指定的類型
const_cast
- 一般用于去除const屬性施符,將const轉(zhuǎn)換成非const,比如
const Object obj1 = new Obejct();
Object * obj2 = static_cast<Object>(obj1);
const Person * pp1 = new Person();
// pp1->age = 10; // error 因?yàn)槭莄onst 對(duì)象
Person * pp2 = const_cast<Person *>(pp1) ;
pp2->display();
pp2->age = 20;
pp2->display();
dynamic_cast
- 一般用于多態(tài)類型的轉(zhuǎn)換往声,有運(yùn)行時(shí)安全檢測(cè)。如果指針轉(zhuǎn)換的時(shí)候戳吝,子類指針類型可以轉(zhuǎn)換成父類浩销,但是父類不能轉(zhuǎn)換成子類。
class Person{
virtual do();
};
class Student:public Person {
};
class Other{
};
Person * aa = new Person();
Person * bb = new Student();
Student * stu1 = dynamic_cast<Student*>(aa);// 返回為NULL
Student * stu2 = dynamic_cast<Student*>(bb);
Other * oth1 = dynamic_cast<Other*>(stu2); // 返回為NULL
//返回為NULL 證明類型轉(zhuǎn)換失敗
reinterpret_cast
- 屬于比較底層的強(qiáng)制轉(zhuǎn)換骨坑,沒(méi)有任何類型檢查和格式轉(zhuǎn)換撼嗓,僅僅是簡(jiǎn)單的二進(jìn)制數(shù)據(jù)拷貝
- 可以交叉轉(zhuǎn)換,可以將指針和整數(shù)互相轉(zhuǎn)換
16、模板
- C++中利用模板來(lái)實(shí)現(xiàn)泛型
- 所謂的泛型欢唾,是一種將類型參數(shù)化以達(dá)到代碼復(fù)用的技術(shù)
- 模板的使用格式如下
template <typename\class T>
typename和class是等價(jià)的
- 模板沒(méi)有被使用時(shí)且警,是不會(huì)被實(shí)例化出來(lái)的
- 模板的聲明和實(shí)現(xiàn)如果分離到.h和.cpp中,會(huì)導(dǎo)致鏈接錯(cuò)誤礁遣,所以一般將模板的聲明和實(shí)現(xiàn)統(tǒng)一放到一個(gè).hpp文件中
17斑芜、智能指針
傳統(tǒng)的指針需要手動(dòng)管理內(nèi)存,非常容易導(dǎo)致內(nèi)存泄露和野指針等問(wèn)題祟霍,針對(duì)這一問(wèn)題杏头,C++采用了智能指針的方案來(lái)解決。
auto_ptr
- auto_ptr 屬于C++98標(biāo)準(zhǔn)沸呐,在C++11 已經(jīng)不推薦使用(有缺陷醇王,比如不能用于數(shù)組)
- auto_ptr對(duì)象生命周期結(jié)束時(shí),其析構(gòu)函數(shù)會(huì)將auto_ptr對(duì)象擁有的動(dòng)態(tài)內(nèi)存自動(dòng)釋放
- 一塊動(dòng)態(tài)內(nèi)存只能被一個(gè)auto_ptr 對(duì)象持有崭添。
shared_ptr
- 被shared_ptr持有的對(duì)象會(huì)產(chǎn)生強(qiáng)引用寓娩,一個(gè)shared_ptr產(chǎn)生一個(gè)強(qiáng)引用計(jì)數(shù)
- 可以通過(guò)shared_ptr的use_count 屬性查看被引用對(duì)象的強(qiáng)引用計(jì)算器
- 當(dāng)有一個(gè)新的shared_ptr指向?qū)ο髸r(shí),對(duì)象的強(qiáng)引用計(jì)數(shù)就會(huì)+1
- 當(dāng)有一個(gè)shared_ptr銷毀時(shí)呼渣,對(duì)象的強(qiáng)引用計(jì)算就會(huì)-1
- 當(dāng)一個(gè)對(duì)象的強(qiáng)引用計(jì)算為0是(沒(méi)有任何shared_ptr指向?qū)ο髸r(shí))棘伴,對(duì)象就會(huì)自動(dòng)銷毀(調(diào)用釋構(gòu))
- shared_ptr 會(huì)產(chǎn)生循環(huán)引用的問(wèn)題,可以通過(guò)weak_ptr解決循環(huán)引用的問(wèn)題
unique_ptr
- unique_ptr也會(huì)對(duì)對(duì)象產(chǎn)生強(qiáng)引用屁置,但是它可以確保同一時(shí)間只有一個(gè)指針指向?qū)ο?/li>
- 當(dāng)unique_ptr銷毀時(shí)(作用域結(jié)束時(shí))焊夸,其指向的對(duì)象也就自動(dòng)銷毀
- 可以使用std::move 函數(shù)轉(zhuǎn)移unique_ptr的所有權(quán)
unique_ptr<Object>ptr1(new Object());
unique_ptr<Object>ptr2 = std::move(ptr1); //轉(zhuǎn)移所有權(quán)
make_shared
利用這個(gè)模板函數(shù)對(duì)智能指針進(jìn)行初始化效率更好
//傳統(tǒng)初始化智能指針的寫(xiě)法
std::shared_ptr<Widget> spw(new Widget);
//利用make_shared 函數(shù)初始化的寫(xiě)法
auto spw = std::make_shared<Widget>();
- 每個(gè)std::shared_ptr都指向一個(gè)控制塊,控制塊包含被指向?qū)ο蟮囊糜?jì)數(shù)以及其他東西蓝角。這個(gè)控制塊的內(nèi)存是在std::shared_ptr的構(gòu)造函數(shù)中分配的阱穗。因此直接使用new,需要一塊內(nèi)存分配給Widget使鹅,還要一塊內(nèi)存分配給控制塊颇象。
- std::make_shared申請(qǐng)一個(gè)單獨(dú)的內(nèi)存塊來(lái)同時(shí)存放Widget對(duì)象和控制塊。這個(gè)優(yōu)化減少了程序的靜態(tài)大小并徘,因?yàn)榇a只包含一次內(nèi)存分配的調(diào)用遣钳,并且這會(huì)加快代碼的執(zhí)行速度,因?yàn)閮?nèi)存只分配了一次麦乞。另外蕴茴,使用std::make_shared消除了一些控制塊需要記錄的信息,這樣潛在地減少了程序的總內(nèi)存占用
18姐直、聯(lián)合體
- 在查看oc runtime源碼發(fā)現(xiàn)倦淀,原來(lái)C++的聯(lián)合體 union 像結(jié)構(gòu)體一樣,可以編寫(xiě)構(gòu)造函數(shù),有private和public關(guān)鍵字声畏,可以編寫(xiě)方法撞叽。姻成。。愿棋。科展。
union aOBJ {
private:
int value;
public:
aOBJ(int value = 0){ this->value = value;};
void say(){ std::cout << "saySomething" << value << std::endl;};
};
19、override關(guān)鍵字
- C++11 中的 override 關(guān)鍵字糠雨,可以顯式的在派生類中聲明才睹,哪些成員函數(shù)需要被重寫(xiě),如果沒(méi)被重寫(xiě)甘邀,則編譯器會(huì)報(bào)錯(cuò)琅攘。