組織政策
0,不拘于小結
縮進, 行的長度,命名,注釋,空格,制表,
1-4,高警告級别幹淨利落地進行編譯,使用建構系統,使用版本控制,代碼審查
風格
5,一個實體應該隻有一個緊湊的職責。 (依賴性管理,繼承,抽象,隐藏)
6,正确簡單清晰
7,
===================
01, 視c++為一個語言聯邦
multiparadigm programming langauge, 支援過程(procedrual),面向對象object oriented, 函數形式functional
,泛型形式generic, 元程式設計metaprogramming
02, 盡量用const 取代enumu,inline替換#define
03, 盡量用const
const成員函數目的,為了該成員函數作用于const對象身上
兩個函數如果常量性不同,可以被重載
const對象大多數用于passed by poiner-to-const, passed by reference-to-const
bit constness,成員函數隻有在不更改任何non-static成員對象才可以說是const,也就是說不更改對象内任何一個bit.
logical constness,一個const成員函數可以修改它所處理的對象内的某些bits,但隻有用戶端偵測不出的情況下才得如此。
mutable 能夠釋放掉non-static 成員變量的bitwise constness限制。
const char & operator[](std::size_t position) const
{
return text[position];
}
char & operator[](std::size_t position)
return const_cast<char&>(static_cast<const TextBlock&>)(this)[position]);
第一次轉型static_cast<const TextBlock&>)(this)
第二次轉換const_cast<char&>
利用const實作non const版本
反向做法不可以。const成員函數承諾不改變其對象的邏輯狀态(logical state),non-const成員函數沒有這樣的承諾。
如果const調用non-const,就冒這樣的風險:你曾經承諾不改動的那個對象被改動了。
編譯器強制實施bitwise constness, 程式設計應該使用概念上的常量性(conceptual constness)
04, 确定對象使用前沒初始化
變量初始化規則,取決于變量類型和位置
1)内置類型變量初始化取決于變量定義的位置,函數體外定義的變量都初始化成0,函數體裡定義的内置類型不進行自動
初始化。
2)類類型變量的初始化,通過構造函數初始化(有預設/無預設需要顯示調用)
non-local-static 對象初始化順序無法确定
對應内置對象手工初始化
使用成員初始值清單,不要在構造函數裡面指派,免除“跨編譯單元之初始化次序”問題,用local static 對象替換
non-local static對象
05,了解c++預設編寫哪些函數
default構造函數,拷貝構造函數,拷貝指派
06,若不使用編譯器自動生成的函數,就該明确拒絕。
uncopable 将構造函數聲明為private
07,為多态聲明virtual 析構函數
08,别讓異常逃離析構函數
09, 絕不在構造函和析構過程中調用virtual函數
可以用private static函數,作為輔助函數給base calss構造函數傳值。
10, 另operator= 傳回一個reference to *this
連鎖指派。這隻是個協定,無強制性。内置标準類型和标準庫都提供
11,在Operator= 中處理自我指派
确定任何函數如果操作一個以上對象,其中多個對象是同一個對象時,執行仍然正确。
12, 複制對象時勿忘其每一個成分
1)複制local成員變量,2)base class内的coppying函數
copy assignment調用copy構造函數是不合理的。因為這就像試圖構造一個已經存在的對象。
copy構造函數調用copy assignment操作同樣無意義。 構造函數用來初始化新對象,而assginment
操作隻實施于已經初始化的對象上。對一個尚未構造好的對象指派,就像在一個尚未初始化的對象上
做“隻對已經初始化對象才有意義”的事情一樣。
如果你發現copy構造函數和copy assignment操作符有相近的代碼,消除重複代碼的做法是,
建立一個新的成員函數給兩者調用。這樣的函數往往是priviate,而且常命名init.
1)copy函數應該確定複制對象内的所有成員變量及base成分
2)不要嘗試以某個copying函數實作另一個copying函數。應該将共同機能放在第三個函數中,
并由copying函數共同調用。
資源管理
檔案描述符,互斥鎖,圖像界面字型筆刷,資料庫,socket
13, 以對象管理資源
獲得資源後立刻放進管理對象auto_ptr RAII resource acquisition is initialization
管理對象運用析構函數確定資源釋放
RCSP reference-couting smart pointer RCSP無法打破環狀引用。
tr1::shared_ptr就是RCSP
為了防止資源洩漏,請使用RAII對象,它們在構造函數中獲得資源并在析構函數中釋放資源
兩個常被使用的RAII classes分别是tr1_shared_ptr和auto_ptr
14, 在資源管理類中心小心copying行為
15,在資源類中提供對資源的通路
RAII class 應該提供取得其管理之資源的辦法
對原始資源的通路可能經由顯示轉換或隐士轉換,一般而言顯示轉換比較安全,隐士轉換對客戶比較
友善
16,對使用new和delete要采用相同的形式
delete pal; delete [] pal;
17,以獨立newed對象需要置入智能指針
以獨立語句将Newed對象置于智能指針内,如果不這樣,一旦異常抛出,有可能導緻難以覺察的資源洩漏
設計與聲明
18,讓接口容易被正确使用,不容易被誤用
理想上,如果客戶企圖使用某個接口卻沒有獲得他所預期的行為,這個代碼不應該通過編譯,反之則是
客戶想要的
接口一緻性。盡量與内置types一緻。
限制類型内什麼事可以做,什麼不可以做,常用const限制。
防止誤用,包括建立新類型,限制類型上的操作,束縛對象值,消除用戶端資源管理責任
tr1::shared_ptr支援定制删除器,可以防範DLL問題,可被用來自動解除互斥鎖。
19 設計class猶如設計type
重載函數,操作符,控制記憶體配置設定,定義對象初始化終結。
新type的對象應該如何被建立銷貨
對象的初始化和對象的指派應該有什麼樣的差别。這個答案決定構造函數和指派操作符的行為
新type對象如果被passed by value,意味着什麼? copy構造函數
什麼是typed的合法值。 class限制條件 invariants.
你新type需要配合某個繼續體系圖麼?
你的type需要什麼樣的轉換?
什麼樣的函數對新type而言合理,memeber函數
什麼樣的标準函數應該駁回, private函數
誰該取用新type成員。public成員
什麼是新type的未聲明接口
你的新type有多麼一般化 class template
你需要一個新type麼?
20,甯以pass-by-reference-to-const 替換pass-by-value
防止産生副本copy構造函數多次調用
防止對象切割,子類被視為基類對象傳遞
這個規則不适用于内置類型
21, 必須傳回對象時,别妄想傳回其reference.
絕不要傳回Pointer或reference指向一個local stack對象,或傳回reference指向
一個heap-allocated對象,傳回pointer或reference指向local static對象有可能
同時需要多個這樣的對象。
22,将成員變量聲明為private
23,甯以non-member ,non-friend替換member函數
資料以及操作資料的那些函數應該捆綁到一塊。
如果某些東西被封裝,它就不再可見。愈多東西被封裝,愈少人可以看到它。而遇少
人看到它,我們就有愈大的彈性去變化它。因為我們改變僅僅直接影響看到改變的那些
人和事物。是以,愈多東西被封裝,我們改變那些東西的能力就愈大。封裝使我們改變
事物隻影響有限客戶。
限制考慮對象資料,愈少代碼可以看到資料(也就是通路它),愈多的資料可以被封裝
,而我們也就遇能自由地改變對象資料,例如改變成員變量的數量,類型等等。如何測量
“有多少代碼可以看到一塊資料”,我們計算能通路該資料的函數,作為一種粗糙的測量。
愈多函數通路它,資料的封裝性愈低。
名字空間可以跨多個源檔案,類不能,類是一個整體不能分割。
prefer non-member non-friend to member,這樣做增加封裝性,包裹彈性,和機能擴充性。
24,若所有參數皆需類型轉換,請為此采用non-member函數
隻有參數被列入參數列,這個參數才是隐式類型轉換的合格參與者。
member的函數反面是non-member,而不是friend.
不能夠隻因為不該成為member,就自動讓它成為friend.朋友帶來的麻煩往往過于其價值。
25,考慮寫出一個不抛出異常的swap函數。
無法偏特化function template.隻能對class template偏特化。
可以重載function template
std::swap 典型實作
namespace std {
template<typename T>
void swap(T& a, T&b)
{
T temp(a);
a = b;
b = temp;
}
如果不指派,隻想拷貝指針pimp.可以對std::swap特化,下面是基本構想,但目前無法通過編譯
namespace std{
template<> void swap<Widget>(Widget &a, Widget& b)
swap(a.pmpl, b.pmpl);
在Wiget類中加一個成員swap函數,這種做法同STL容器一緻。
class Widget {
public:
void swap(Widget & other)
{
using std::swap;
swap(pImpl, other.pImpl);
}
};
如果類Widget 和 WidgetImp是模闆
template<T>
class WidgetImp {...};
class Widget{...};無法在std内添加重載模闆,違反标準。
namespace WidgetStuf
...
class Widget {...};
void swap(widget<T> a, widget<T>b)
a.swap(b);
如果打算置換兩個widget對象,根據c++名字查找法則 name lookups rules. argument-dependent lookup或koening lookup法則
pimp pointer to implementation.
本文轉自莫水千流部落格園部落格,原文連結:http://www.cnblogs.com/zhoug2020/p/6055074.html,如需轉載請自行聯系原作者