1. 譯序
C++是一個難學易用的語言。
C++的難學,展現在廣博的文法,背後的語義;語義背後的深層思維;深層思維背後的對象模型。
C++四種不同而又相輔相成的程式設計泛型:基于過程型,基于對象型,面向對象型,一般模型。
衍生的複合術語:base class,derived class,super class,subclass,class templates等。
object和type,中譯詞“對象”和“類型”。更貼切的是“物件”和“型别”。
2. 導讀部分
本書的目的是探讨如何有效運用C++。書中提出的忠告有兩類:一般性的設計政策和帶有具體細節的特定語言特性。
設計上的讨論大多是選擇題,不同做法完成同一件工作的情況下,選擇:
inheritance(繼承)還是templates(模闆)。
public繼承還是private繼承。
private繼承還是composition(複合)。
member函數還是non_member函數。
pass_by_value還是pass_by_reference。
3. 條款一:讓C++成為一個語言聯邦
C++發展與C with class,但擁有不同于C with class的觀念,特性和程式設計戰略,比如Exceptions,templates,STL等。
C++多重範型程式設計語言:過程型(procedural)面向對象型(object-oriented)函數型(functional)泛型(generic)元程式設計型(metaprogramming)。
C++能力強大,彈性十足,但所有适當的方法都有例外,合理運用這些強大的特性,方法是将C++視為由相關語言組成的聯邦。
C++語言主要的次語言:
C:C++有時解決問題的方式是進階的C語言,但是C缺乏進階特性。
Object-Oriented C++:這部分是C with class的訴求。classes(構造析構)encapsulation(封裝)inheriance(繼承)polgmorphism(多态)virtual函數(動态綁定)
Template C++:C++泛型程式設計部分,template威力強大,能帶來嶄新的程式設計範式,TMP:模闆元程式設計。
STL:STL是template程式庫,它對容器(containers)疊代器(iterators)算法(algorithms)以及函數對象(function-objects)的規約有很強的緊密配合與協調。
準則:
C-like(内置類型)而言:pass_by_value 比 pass_by_reference進階。
C part of C++移往Object-Oriented C++,由于構造和析構存在,pass_by_reference_to_const往往更好。
Template C++尤其如此。
STL中,疊代器和函數對象都在C指針上構造的,舊式的C pass_by_value再次适用。
4. 條款二:盡量以const eunm inline 替換 #define
#define 不被視為語言的一部分。define的名稱不在符号表中,由于define定義值引發的問題将很難定位。
常量替代宏 const double ASP = 1.653;
兩種特殊的情況:①定義常量指針,有必要把指針也聲明為cosnt。②class專屬常量,需要聲明為靜态成員。作用域也限定在了class中。
#define無法建立一個class專屬常量,#define并不重視作用域。
舊式編譯器可能不允許在其聲明式上獲得初值,替代方法是“the enum hack”。
取代宏函數的方案:template inline函數。
單純常量,以const對象或者enum替換#define。
形似函數的宏,改用inline函數替代#define。
5. 條款三:盡可能使用const
const文法變化多端,但是并不高深莫測。const在星号左邊,被指物是常量。const在星号右邊,指針自身是常量。
const出現在類型名的兩側時,效果是一樣的。
STL疊代器和const:STL疊代器是以指針為根據塑模出來的,疊代器等同于T*。
const面向函數聲明時的應用:const與傳回值,參數,函數自身(成員函數)關聯。
傳回值是const:函數傳回值不期望被修改時使用,多用于左值的運算符重載,例如 * 的重載。這種情況下參考基礎類型在相同情況的的表現。
const成員函數:
const成員函數的目的是确認該函數可用于const對象上。
可以知道哪個函數可以修改對象的内容,而哪些不行。
使操作cosnt對象稱為可能。
兩個成員函數隻是常量性不同,可以被重載,const是函數簽名的一部分。
實際程式中,const對象大多用于passed by pointer_to_const 或者 passed by reference_to_const的傳遞結果。
成員函數時const,分為兩種概念行為,bitwise constness 和 logical constness
bitwise const 認為成員函數不修改任何成員變量時,才能說是const,符合C++對常量性的定義。const成員函數不能修改任何non-static成員變量。
很多函數不十足具備bitwise const特性,卻能通過bitwise測試,例如函數傳回指針成員所指向的内容,在函數外部可以修改成員值。
以上的情況導出了logical constness,const成員函數可以修改它所處理的對象内部某些bit,但是隻有在用戶端監測不到時才能如此。
對象有在const成員函數中修改no-static成員的需求,C++引入了mutable,釋放了no-staic成員變量的bitwise constness 限制。
在const和non-const成員函數中避免重複
當成員函數需要const版本和非const版本時,使用const版本實作non-const版本。
步驟:實作const版本;傳回類型為const引用;函數類型是const。實作non-const版本;使用static_cast把*this轉為const;通路成員;對成員類型進行const_cast,去const屬性。
反向的const調用non-const模闆是錯誤的,違反了const的本質屬性。
6. 條款四:确定對象被使用前已經被初始化
指派和初始化的差別:構造函數内部都叫指派,在初始化清單中的行為叫初始化。
C++有固定的成員函數初始化次序。base class 早于 derived classes。成員的初始化清單按聲明次序初始化。
non-local static對象初始化次序:
函數内部的static對象時local static,其餘的static對象都是non-local static。
兩個non-local static 互相依賴(處于不同的編譯單元),兩個對象的初始化次序沒有明确的定義。
解決這類情況的方式是把static對象放在static函數中定義傳回。