1.盡量使用初始化列表而不要再建構函式裡賦值,初始化順序和宣告的順序一致,一些型別如const,引用等,必須使用初始化。對於非內部資料型別成員物件應當採用初始化表,以獲取更高的效率。
example:
b::b(const a& a):m_a(a){}只呼叫了類a的拷貝建構函式
2.基類都使用虛析構函式,這樣才能在使用多型時,準確的析構派生類
3.operator>>和operator《決不能是成員函式。如果f是operator>>或operator<<,讓f成為非成員函式。如果f還需要訪問c的非公有成員,讓f成為c的友元函式。在類的內部,它可以用於靜態和非靜態成員。
4.盡可能使用const.const關鍵字實在是神通廣大。在類的外面,它可以用於全域性或名字空間常量,以及靜態物件(某一檔案或程式塊範圍內的區域性物件)。在類的內部,它可以用於靜態和非靜態成員.
對指標來說,可以指定指標本身為const,也可以指定指標所指的資料為const,或二者同時指定為const,還有,兩者都不指定為const:
char *p = "hello"; // 非const指標,
// 非const資料
const char *p = "hello"; // 非const指標,
// const資料
char * const p = "hello"; // const指標,
// 非const資料
const char * const p = "hello"; // const指標,
// const資料
5.盡量用「傳引用」而不用「傳值」
「通過值來傳遞乙個物件」的具體含義是由這個物件的類的拷貝建構函式定義的。這使得傳值成為一種非常昂貴的操作。
為避免這種潛在的昂貴的開銷,就不要通過值來傳遞物件,而要通過引用:
const student& returnstudent(const student& s)
這會非常高效:沒有建構函式或析構函式被呼叫,因為沒有新的物件被建立。
6.返回值:對於賦值函式,應當用「引用傳遞」的方式返回物件,對於相加函式應當用值傳遞,因為引用物件在函式結束時被銷毀。
例如:
classstring
//string的賦值函式operate = 的實現如下:
string & string::operate=(const string &other)
對於賦值函式,應當用「引用傳遞」的方式返回string物件。如果用「值傳遞」的方式,雖然功能仍然正確,但由於return語句要把 *this拷貝到儲存返回值的外部儲存單元之中,增加了不必要的開銷,降低了賦值函式的效率。例如:
string a,b,c;
… a = b; // 如果用「值傳遞」,將產生一次 *this 拷貝
a = b= c; // 如果用「值傳遞」,將產生兩次 *this 拷貝
對於相加函式,應當用「值傳遞」的方式返回string物件。如果改用「引用傳遞」,那麼函式返回值是乙個指向區域性物件temp的「引用」。由於temp是在棧上申請的變數,函式執行完畢後被銷毀,將導致返回的「引用」無效。
//string的相加函式operate + 的實現如下:
string operate+(const string &s1, const string &s2)
如果函式返回值是乙個物件,要考慮return語句的效率。例如
return string(s1 + s2);
這是臨時物件的語法,表示「建立乙個臨時物件並返回它」。不要以為它與「先建立乙個區域性物件temp並返回它的結果」是等價的,如
string temp(s1 + s2);
return temp;
實質不然,上述**將發生三件事。首先,temp物件被建立,同時完成初始化;然後拷貝建構函式把temp拷貝到儲存返回值的外部儲存單元中;最後,temp在函式結束時被銷毀(呼叫析構函式)。然而「建立乙個臨時物件並返回它」的過程是不同的,編譯器直接把臨時物件建立並初始化在外部儲存單元中,省去了拷貝和析構的化費,提高了效率。
7.劃分全域性名字空間的好處
例如,假設library1.h定義了一些常量,其中包括:
const double lib_version = 1.204;
類似的,library2.h也定義了:
const int lib_version = 3;
很顯然,如果某個程式想同時包含library1.h和library2.h就會有問題。
要這麼做:
namespacesdm ;
handle&gethandle();
}
使用者於是可以通過三種方法來訪問這一名字空間裡的符號:將名字空間中的所有符號全部引入到某一使用者空間;將部分符號引入到某一使用者空間;或通過修飾符顯式地一次性使用某個符號:
voidf1()
void
f2()
void
f3()
8.將檔案間的編譯依賴性降至最低
假設某一天你開啟自己的c++程式**,然後對某個類的實現做了小小的改動。提醒你,改動的不是介面,而是類的實現,也就是說,只是細節部分。然後你準備重新生成程式,心想,編譯和鏈結應該只會花幾秒種。畢竟,只是改動了乙個類嘛!於是你點選了一下"rebuild",或輸入make(或其它類似命令)。然而,等待你的是驚愕,接著是痛苦。因為你發現,整個世界都在被重新編譯、重新鏈結!
在name.h中定義
class name{};
在person.h中:
#include"name.h
"class
person;
在其他檔案中:
class man:public person;
class woman:public person;
這時候person檔案和name.h之間建立了編譯依賴關係,如果name改變了它的實現,或者name依賴的類改變了實現,包含person類的檔案以及任何使用了person類的檔案就必須重新編譯。這時person,man,和woman的檔案都要重新編譯。
為了實現定義與實現細節分開,我們可以這樣定義person:
class name;//提前宣告
class
person;
如果這樣做可行,person的使用者就不需要重新編譯,只可惜用起來才知道:
intmain()
當看到x的定義時,編譯器知道必須為它分配乙個int大小的記憶體。這沒問題,每個編譯器都知道乙個int有多大。然而,當看到p的定義時,編譯器雖然知道必須為它分配乙個person大小的記憶體,但怎麼知道乙個person物件有多大呢?
對應於上面的**,或許可以這樣做:
intmain()
下面具體介紹怎麼採用這一技術來實現person介面和實現的分離:
class name;//提前宣告
class
man;
class
woman;
class
person;
//在person.cpp中:
#include
"person.h
"#include
"man.h
"person.cpp::person(
const name&_pname)
string person::namestr()const
這樣,person作為介面與實現完全分離。編譯時不對name的改變產生依賴
記憶體管理學習筆記
1.棧 堆和靜態區 靜態區 儲存自動全域性變數和static變數 包括全域性靜態變數和區域性靜態變數 靜態區的內容在整個程式的生命週期內都存在。棧 儲存區域性變數。棧上的內容只在函式的範圍內存在,當函式執行結束,這些內容也會自動被銷毀。其特點是效率高,但是空間大小有限。堆 由malloc系列函式或n...
cocos記憶體管理學習
口訣 1.誰建立,誰釋放。通過new或者clone建立的物件,必須呼叫release或者autorelease。2.new,clone以外的方法建立的物件都被宣告了autorelease。3.誰retain,誰release。無論這個物件是如何生成的,只要呼叫了retain就要呼叫release。正...
object c 記憶體管理學習筆記
nsautoreleasepool pool nsautoreleasepool alloc init pool drain 這個函式可以把autoreleasepool裡的物件釋放 在for迴圈中每次都釋放記憶體池的示例 nsautoreleasepool temppool for i 0 i a...