第一章介紹 C++ 的一些基本方式洛搀。
1. 視 C++ 為一個語言聯(lián)邦
現(xiàn)在 C++ 已經(jīng)是個多重泛型編程語言敢茁,同時支持過程、面向?qū)ο罅裘馈⒑瘮?shù)彰檬、泛型伸刃、元編程形式。將其視為語言聯(lián)邦逢倍,主要有四個次語言:
-
C
區(qū)塊捧颅、語句、預(yù)處理较雕、內(nèi)置數(shù)據(jù)類型碉哑、數(shù)組、指針都來自C亮蒋。此時傳值比傳引用高效扣典。 -
Object-Oriented C++
類(構(gòu)造、析構(gòu)函數(shù))慎玖、封裝贮尖、繼承、多態(tài)趁怔、虛函數(shù)湿硝。傳引用比傳值高效。
-Template C++
新的編程范型:模板元編程 -
STL
容器痕钢、迭代器图柏、算法、函數(shù)對象任连。傳值更高效。
總結(jié):
C++ 高效編程守則視狀況而變化例诀,取決于使用 C++ 的哪一部分随抠。
2. 盡量以const, enum, inline 替換 #define
寧可以編譯器替換預(yù)處理器。#define不被視為語言的一部分繁涂,所以編譯出錯時難以查找拱她。如:
#define ASPECT_RATIO 1.653
應(yīng)換為
const double AspectRatio = 1.653
此時AspectRatio會進(jìn)入編譯器的記號表,而且對于浮點(diǎn)數(shù)使用常量可能比 #define 碼量更小扔罪。常量替換 #define 的兩種特殊情況:
-
定義常量指針
例如定義一個常量的char *-based字符串:
-
class專屬常量
為了將常量的作用域限制在class中秉沼,需將其設(shè)為class的一個成員;要確保其只有一份實(shí)體矿酵,需聲明為static成員唬复。
產(chǎn)生一整群函數(shù),每個函數(shù)接受兩個同型對象测砂。
總結(jié)
- 對于單純常量茵烈,最好以const對象或enums替換#define
- 對于形如函數(shù)的宏,最好改用inline函數(shù)替換#define
3. 盡可能使用const
關(guān)鍵詞const 用于指定一個不該被改動的對象砌些,加上這個約束后編譯器會強(qiáng)制保證實(shí)施瞧毙。所以只要某個值確定應(yīng)該不變,就應(yīng)該加上以得到編譯器的幫助寄症。
當(dāng)const和指針組合時:
- const出現(xiàn)在星號左邊——被指物是常量
- const出現(xiàn)在星號右邊——指針自身是常量
- 兩邊都有——被指物和指針都是常量
以相對指針的位置來判斷宙彪,所以以下兩種寫法相同:
當(dāng)const和STL迭代器組合時:迭代器的作用就像是 T* 指針。const 迭代器 = T* const 指針有巧,表示這個迭代器不得指向不同的東西释漆,但所指對象的值可變。如:
當(dāng)const和函數(shù)聲明組合時:返回一個常量值
const成員函數(shù)
const用于成員函數(shù)是為了保證該函數(shù)可作用于const對象逊笆。這類函數(shù)重要的理由:
- 使class接口比較容易被理解
- 使操作const對象成為可能
錯誤在于企圖對由const版的operator[]返回的const char &施行賦值。
const成員函數(shù)的兩種概念:
-
bitwise constness認(rèn)為成員函數(shù)只有在不更改對象的任何成員變量時才能稱為const镊掖。所以const成員函數(shù)不能更改對象內(nèi)任何non-static成員變量乃戈。
但一個更改了指針?biāo)肝锏某蓡T函數(shù)雖然不算const,若只有指針屬于對象亩进,那么不會引發(fā)編譯錯誤症虑。
最終改變了常量對象的值。
-
logical constness
由于存在以上的錯誤归薛,這里主張一個const成員函數(shù)可以修改它所處理的對象內(nèi)的某些bits谍憔。如:
在const和non-const成員函數(shù)中避免重復(fù)
有時候成員函數(shù)需要進(jìn)行多個步驟习贫,這就造成const和non-const成員函數(shù)存在大量重復(fù):值得注意的是反向調(diào)用是錯誤的月而。用const調(diào)用non-const冒著對象被改的風(fēng)險汗洒。
總結(jié)
- 將某些東西聲明為const可幫助編譯器偵測出錯誤用法。const可被施加于任何作用域內(nèi)的對象父款、函數(shù)參數(shù)溢谤、函數(shù)返回類型、成員函數(shù)本體憨攒。
- 編譯器強(qiáng)制實(shí)施bitwise constness世杀,但編寫程序時應(yīng)使用概念上的常量性。
- 當(dāng)const和non-const成員函數(shù)有著實(shí)質(zhì)等價的實(shí)現(xiàn)時肝集,令non-const版本調(diào)用const版本可避免代碼重復(fù)瞻坝。
4. 確定對象使用前已先被初始化
C++ 變量在聲名時有時會被初始化有時不會,需手工完成杏瞻。此時省去了default構(gòu)造的過程浮创,都進(jìn)行copy構(gòu)造。也可在列用default構(gòu)造:
而且如果成員變量是const或reference就一定需要初值砌函,不能被賦值斩披。所以最簡單的做法就是:總是使用成員初值列。
C++ 也有固定的成員初始化次序:基類早于子類胸嘴,類的成員變量總是以其聲明次序被初始化雏掠。
non-local static對象的初始化次序
所謂static對象,壽命從被構(gòu)造出來到程序結(jié)束為止劣像。也包括global對象,其中函數(shù)內(nèi)的static對象為local的摧玫。它們的析構(gòu)函數(shù)會在main函數(shù)結(jié)束時自動調(diào)用耳奕。此時就必須保證tfs在tempDir之前被初始化。正確的做法是 將每個non-local static對象搬到自己的專屬函數(shù)內(nèi)诬像,即用local static對象替換non-local static對象屋群。這么做的基礎(chǔ)是:C++ 保證函數(shù)內(nèi)static對象會在該函數(shù)被調(diào)用期間首次遇上該對象的定義式時被初始化。如:
現(xiàn)在使用函數(shù)返回的指向static對象的reference坏挠,而不再使用static對象自身芍躏。
所以為了避免初始化之前使用對象需要做:
- 手工初始化內(nèi)置型non-member對象
- 使用成員初值列對付對象的所有成分
- 在初始化次序不確定時用函數(shù)返回的指向static對象的reference。
總結(jié)
- 為內(nèi)置型對象進(jìn)行手工初始化降狠,C++不保證初始化对竣。
- 構(gòu)造函數(shù)最好使用成員初值列庇楞,不要再構(gòu)造函數(shù)本體內(nèi)用賦值操作。初值列列出的變量次序應(yīng)與聲明次序同
- 為免除“跨編譯單元的初始化次序”問題否纬,用local static對象替換non-local static對象吕晌。