天天看點

Effective C++ Part1

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函數中定義傳回。

繼續閱讀