01:視c++爲一個語言聯邦
爲了理解C++,必需要認識其主要的次語言:c++
- C
說到底C++還是以C爲基礎。區塊,語句,預處理器,內置數據類型,數組,指針通通來自C。
- Object-Oreinted C++
這一部分是面向對象設計之古典守則在C++上的最直接實施。類,封裝,繼承,多態,virtual函數等等...
- Template C++
這是C++泛型編程部分。
STL
STL是個template程序庫。包含容器(containers),迭代器(iterators),算法(algorithms)以及函數對象(function objects)...
這四個次語言,當你從某個次語言切換到另外一個,致使高效編程守則要求你改變策略。C++高效編程守則視情況而變化,取決於你使用C++的哪一部分。
例如:當對內置(C-like)類型而言,pass-by-value比pass-by-reference高效。但當你從C part of C++移往Object-Oriented C++,因爲user-defined構造函數和析構函數的存在,pass-by-reference-to-const每每更好。運用template C++ 時尤爲如此。然而對STL的迭代器和函數對象而言,舊式的pass-by-value守則再次適用。算法
請記住
C++高效編程守則視情況而變化,取決於你使用C++的哪一部分。編程
02:儘可能以const,enum,inline替換#define
#define M 1.1
記號M也許從未被編譯器看見,也許在編譯器開始處理源碼以前它就被預處理器移走了。所以M可能壓根就就沒進入符號表(symbol table)。當你使用該常量但產生編譯錯誤時,錯誤信息可能只提到1.1而不是M。若被定義在某個頭文件中,就很難發現錯誤所在。
解決之道:數組
const double M=1.1;
做爲語言常量,M確定會被編譯器看到,天然也就必定會進入符號表。另外,使用常量還能夠避免宏替換帶來的多份目標碼(object code)問題。安全
兩種特殊狀況函數
- 定義常量指針
因爲常量表達式一般被放在頭文件內,所以有必要將指針(不只是指針所指之物)聲明爲const。
例如:
const char* const authorName="Scott Meyers";
- class專屬常量
爲了限制做用域於class內,必須讓它成爲class的一個成員,爲了確保只有一份,必須加上static修飾符。
class GamePlayer
{
static const int NumTurns=5;
int scores[Numturns];
};
若是你須要取這個常量的地址或者是編譯器堅持要看到一個定義式,你就必須在實現文件中提供以下定義:學習
const int GmaePlayer::NumTurns;
若是編譯器不支持static成員在聲明式上得到初始值,那麼只好放在定義式上。但當你在class編譯期間須要一個class常量值,能夠採用the enum hack:this
class GamePlayer
{
enum{NumTurns=5};
int scores[Numturns];
};
關於the enum hack,有幾點須要瞭解:設計
- 對一個enum取地址是不合法的,所以能夠做爲不容許獲取pointer或reference的約束。
- 是模板元編程的基礎技術(template metaprogramming)
另外一個問題是用#define實現宏。(這裏沒有使用原書中的例子)指針
#define SUB(a,b) a-b
對於以上宏定義,試問F(4-1,3)*2
結果爲多少?按照直觀理解,你可能會理所固然的認爲是0。但當咱們寫出展開式後:4-1-2*2
,顯然結果是-1。
爲了不這種問題,只好給參數加上括號:
#define SUB(a,b) ((a)-(b))
不管什麼時候當你寫出這種宏,就必須爲全部實參加上小括號,但即便是加上小括號,有時也會出現問題。
如今咱們可使用template inline解決這一點:
template<typename T>
inline auto SUB(const T& a,const T& b) -> decltype(a-b)
{
return a-b;
}
請記住
- 對於單純常量,最好以const對象或enums替換#defines。
- 對於形似函數的宏,最好改用inline函數替換之。
03:儘量使用const
04:肯定對象被使用前已先被初始化
05:瞭解C++默默編寫並調用哪些函數
06:若不想使用編譯器自動生成的函數,就該明確拒絕
07:爲多態基類聲明virtual析構函數
08:別讓異常逃離析構函數
09:毫不在構造和析構的過程當中調用virtual函數
10:令operator= 返回一個reference to *this
11:在operator=中處理自我賦值
12:複製對象時勿忘其每個成分
13:以對象管理資源(RAII)
14:在資源類中當心coping行爲
15:在資源類中提供對原始資源的訪問
16:成對使用new和delete時要採用相同形式
17:以獨立語句將newed對象置入智能指針
18:讓接口容易被正確使用,不易被誤用
19:設計class猶如設計type
20:寧以pass-by-reference-to-const替換pass-by-value
21:必須返回對象時,別妄想返回其reference
22:將成員變量聲明爲private
23:寧以non-member、non-friend替換member函數
24:若全部參數皆要類型轉換,請爲此採用non-member函數
25:考慮寫出一個不出異常的swap函數
26:儘量延後變量定義式的出現時間
27:儘可能少作轉型操做
28:避免返回handles指向對象內部成分
29:爲異常安全而努力是值得的
30:透徹瞭解inlining的裏裏外外
31:將文件間的編譯依存關係降到最低
32:肯定你的public繼承塑模出is-a關係
33:避免遮掩繼承而來的名稱
34;區分接口繼承和實現繼承
35:考慮virtual函數之外的其餘選擇
36:毫不從新定義繼承來的的non-virtual函數
37:毫不從新定義繼承而來的缺省參數值
38:經過複合塑模出has-a或根據某物實現出
39:明智而審慎地使用private繼承
40:明智而審慎地使用多重繼承
41:瞭解隱式接口和編譯器多態
42:解誒typename的雙重意義
43:學習處理模板化基類內的名稱
44:將與參數無關的代碼抽離template
45:運用成員模板接受全部兼容類型
46:須要類型轉換時請爲模板定義非成員函數
47:請使用traits classes表現類型信息
48:認識template元編程
49:瞭解new-handler的行爲
50:瞭解new和delete的合理替換時機
51:編寫new和delete時需固守常規
52:寫了placement new 也要寫placement delete
53:不要輕視編譯器的警告
54:讓本身熟悉包括TR1在內的標準程序庫
55:讓本身熟悉boost