畢業(yè)設(shè)計(jì)中途重讀了幾本以前看過的書,需要做些筆記做日后查閱時使用。
偶然看到 Justin 寫的《Effective C++》筆記,為方便就結(jié)章轉(zhuǎn)載在此。
========================
Effective C++ C++
書作者:Scott Meyers
原筆記作者:Justin : http://m.shnenglu.com/note-of-justin/
========================
Item 1 :C++是一個語言聯(lián)邦
--------------------------
tag: c c++組成
C
區(qū)塊(blocks)、語句(statements)、預(yù)處理器(preprocessor)、內(nèi)置數(shù)據(jù)類型(built-in data types)、數(shù)組(arrays)、指針(pointers)。
Object-Oriented C++
classes(包括構(gòu)造、析構(gòu))、封裝(encapsulation)、繼承(inheritance)、多態(tài)(polymorphism)、virtual函數(shù)(動態(tài)綁定)
Template C++
泛型編程(generic programming) Template metaprogramming(TMP,模版元編程)
STL
容器(containers)、迭代器(iterators)、算法(algorithms)、函數(shù)對象(function objects)
每個語言都有自己的次規(guī)則
Item 2 :用const、enum和模板inline推翻#define的統(tǒng)治
---------------------------------------------------
tag: const enum inline #define
需要定義常量時,不要用#define,改用const修飾的變量或是用enum吧
要想寫一些簡短小函數(shù)時,別考慮#define啦,改用template+inline吧
原因是若為浮點(diǎn)變量,用const減小了代碼大小,同時還使得封裝(encapsulation)變得可行(宏被定義后,在之后的編譯過程都有效,除非undef ),而且,在調(diào)試的時候,因?yàn)閏onst定義的變量是會加在符號表(Symbol Table)的,就比define常量要方便跟蹤了(在預(yù)處理階段,常量的名字就已經(jīng)被替換掉了)
在一些特定的情況下(編譯器不允許“static整數(shù)型class常量”完成“in class 初值設(shè)定” ),如果不能用const取代#define,就用enum。除了不能獲取一個enum的地址之外,這種方法和const的用法其實(shí)差不多。
可以取一個const的地址,不能取一個enum的地址,通常不能取一個#define的地址。
inline函數(shù)和宏有個共同的地方,他們都不會有函數(shù)調(diào)用的棧的開銷。再喊上模板(template)來幫忙,就不用去考慮實(shí)際調(diào)用時的參數(shù)類型。
Item 3 :盡可能使用const
--------------------------------------------------
tag: const non-const conceptual constness mutable
·首先要知道const可以通用在對象上,函數(shù)參數(shù)和返回值上,甚至是用在限制函數(shù)本身。
·const 出現(xiàn)在星號左邊,表式被指物是常量;出現(xiàn)在星號右邊,指針自身是常量;
·兩個成員函數(shù)如果只是常量性(constness)不同,可以被重載。
·const和non-const成員函數(shù)的實(shí)現(xiàn)等價時,可以用non-const版本調(diào)用const版本避免代碼重復(fù)。
Compilers enforce bitwise constness, but you should program using conceptual constness.
這里有提到constness(常量性)的兩個門派: bitwise學(xué)院派和conceptual實(shí)用派。
bitwise constness陣營應(yīng)該都是很學(xué)究的,這里認(rèn)為如果一個函數(shù)被聲明是const,你就絕對不能修改對象里的任何成員(static成員除外)。
主張conceptual constness流的當(dāng)然都比較好說話,雖然你是const黨,但需要的時候,還是應(yīng)該有例外的嘛。正所謂人無完人,const也沒有絕對的const~
conceptual constness可以這樣解釋:具備conceptual constness的對象/函數(shù),其行為對于該對象/函數(shù)以外的數(shù)據(jù)是const的,不會篡改別人的東東。但是不保證它 不會修改對象/函數(shù)內(nèi)部的成員:當(dāng)這些成員用mutable修飾的時候,我們可以在一個const函數(shù)中修改這些mutable成員的值。
所以說這樣的constness是概念上的,實(shí)際上在這樣的函數(shù)中有可能改變了一些變量的值,只不過沒有與它聲稱的constness矛盾而已。
用mutable限定的對象,哪怕是在const函數(shù)里,一樣可以修改!
和const有關(guān)的還有在const和非const對象間的轉(zhuǎn)換問題(用const_cast和static_cast完成兩個方向的轉(zhuǎn)換),不過層次太高,我還沒能看到有需要用的地方
const char& operator[](size_t position) const {
...
}
char& operator[](size_t position) //調(diào)用已經(jīng)實(shí)現(xiàn)的const op[]
{
return const_cast<char&> ( //將const op[] 的返回值中移除 const
static_cast<const CClass&>(*this) //將*this轉(zhuǎn)型為 const,指明調(diào)用的是const版本的op[]
[position] );
}
Item 4 :對象初始化
--------------------------------------------
tag:local static , 初始化列表, 賦值(assignment)
·對于內(nèi)建的對象類型,手工初始化。
·對于對象自身的成員,推薦的方法是在構(gòu)造函數(shù)的初始化列表。
·以logcal static 對象替換 non-local static對象,以避免“跨編譯單元之初始化次序”問題。
賦值(assignment)的效率要比初始化(initialization)低,因?yàn)榍罢呦葮?gòu)造了對象再對他們賦值,在構(gòu)造的同時就也把值賦了。這里還沒加上拷貝構(gòu)造函數(shù)的可能開銷,還有一些類型如const變量、引用(reference)是不能用賦值的形式“初始化”的……
如果在初始化某個對象的時候,有對其他對象是否有初始化的依賴(對不起,這里有點(diǎn)拗口),一定要確保其中所依賴的對象已經(jīng)初始化完畢。
當(dāng)不同的對象的初始化存在相互依賴時,某個對象沒有初始化有可能導(dǎo)致另外一個對象初始化的失敗。
當(dāng)初始化涉及到非局部靜態(tài)對象(non-local static object)時,問題更加明顯:非局部靜態(tài)對象如果定義在不同的文件中,他們就有可能位于不同的編譯單元(translation unit),因?yàn)檫@些對象到底誰先被初始化是不可預(yù)知的。
編譯單元(translation unit):產(chǎn)出單一目標(biāo)文件(single object file)的那些源碼,通常為單一源碼文件加上所包含的頭文件。
解決此類問題的一個方法是:把非局部靜態(tài)對象轉(zhuǎn)換為局部靜態(tài)對象(local static object),也就是把它的定義放在一個函數(shù)里。然后緊接著在這個函數(shù)返回該對象的引用。C++語言規(guī)定在調(diào)用一個含有局部靜態(tài)對象的函數(shù)時,其中的所有局部靜態(tài)對象都必須初始化。這個方法就是利用這一特性,將原本對一個非局部靜態(tài)對象的訪問,轉(zhuǎn)換為對一個函數(shù)的調(diào)用,這個函數(shù)會返回該靜態(tài)對象的引用,并且保證這個對象已經(jīng)被初始化了。
如果需要初始化一個非局部靜態(tài)對象,就把它放到一個函數(shù)里,讓這個函數(shù)簡單的返回這個對象的引用。
posted on 2010-03-15 22:43
Euan 閱讀(601)
評論(0) 編輯 收藏 引用 所屬分類:
C/C++