6 命名約定 Naming
最重要的一致性規則是命名管理govern naming; 命名風格快速獲取名字代表是什麼: 類型? 變量, 函數, 常量, 宏, ...甚至不需要去查找類型聲明; 大腦中的模式匹配引擎pattern-matching engine可以非常可靠的處理這些命名規則;
命名規則具有一定隨意性, 但相比按個人喜好命名, 一致性更重要, 所以不管你怎麼想, 規則總歸是規則;
6.1 通用命名規則 General Naming Rules
Tip 函數命名, 變量命名, 文件命名應局部描述性descriptive; 不要過度縮寫; 類型和變量應該是名詞, 函數名可以用"命令性"動詞;
儘可能給出描述性的名稱; 不要花心思去節省行空間, 讓你的代碼立刻能被理解要重要得多; 不要使用容易引起歧義的縮寫, 或者對項目外的讀者陌生的縮寫, 不要簡單地刪除幾個字符來做出一個簡寫名稱;
1
2
|
int num_errors; //
Good. "num" is a widespread convention. int num_completed_connections; //
Good. |
糟糕的命名使用含糊的縮寫或隨意的字符:
1
2
3
|
int n; //
Bad - meaningless. int nerr; //
Bad - ambiguous abbreviation. int n_comp_conns; //
Bad - ambiguous abbreviation. |
類型和變量名一般爲名詞: 如 FileOpener, num_errors;
函數名通常是指令性的(確切的說它們應該是命令), 如 OpenFile(), set_num_errors(); 取值函數是個特例(在函數命名處詳細闡述), 函數名和它要取值的變量同名;
縮寫:
除非該縮寫在其他地方都非常普遍, 否則不要使用; 例如:
1
2
3
4
|
// Good // These show proper names with no abbreviations. int num_dns_connections; //
大部分人都知道 "DNS" 是啥意思. int price_count_reader; //
OK, price count. No abbreviation |
WARNING
1
2
3
4
5
|
// Bad! // Abbreviations can be confusing or ambiguous
outside a small group. int wgc_connections; //
Only your group knows what this stands for. int pc_reader; //
Lots of things can be abbreviated "pc". int cstmr_id; //
Deletes internal letters. |
永遠不要用省略字母的縮寫:
1
2
|
int error_count; //
Good. int error_cnt; //
Bad. |
6.2 文件命名 File Names
Tip: 文件名要全部小寫, 可以包含下劃線 _ 或連字符 - , 按項目約定來; 如果原本沒有一致的規律, 建議用 "_";
可接受的文件命名:
1
2
3
4
|
my_useful_class.cc my-useful- class .cc myusefulclass.cc myusefulclass_test.cc //
_unittest and _regtest are deprecated. |
C++文件要以 .cc結尾, 頭文件以 .h結尾;
[Add] 需要以文本textually形式包含到特定位置的文件應該以 .inc結尾; 參考self-contained headers <<
不要使用已經存在於 /usr/include下的文件名; (譯註: 即編譯器搜索系統頭文件的路徑), 如 db.h;
通常應儘量讓文件名更加明確; http_server_logs.h就比 logs.h要好; 定義類時文件名一般成對出現, 如 foo_bar.h和 foo_bar.cc, 對應於類 FooBar;
內聯函數必須放在 .h文件中; 如果內聯函數比較短, 就直接放在 .h中; 如果代碼比較長, 可以放到以 -inl.h 結尾的文件中; 對於包含大量內聯代碼的類, 可以使用三個文件:
1
2
3
|
url_table.h //
The class declaration. url_table.cc //
The class definition. url_table-inl.h //
Inline functions that include lots of code. |
參考 -inl.h文件一節;
6.3 類型命名 Type Names
Tip 類型名稱的每個單詞首字母均大寫, 不包含下劃線underscore: MyExcitingClass, MyExictingEnum;
所有類型命名 -- 類, 結構體, 類型定義(typedef), 枚舉--均使用相同約定convention; [Add] 類型名字應該由一個大寫字母開始, 每個新單詞都以大寫字母開頭, 沒有下劃線<<<例如:
1
2
3
4
5
6
7
8
9
10
|
// classes and structs class UrlTable
{ ... class UrlTableTester
{ ... struct UrlTableProperties
{ ... // typedefs typedef hash_map<UrlTableProperties
*, string> PropertiesMap; // enums enum UrlTableErrors
{ .. |
6.4 變量命名 Variable Names
Tip 變量名一律小寫, 單詞之間用下劃線連接; 類(而非結構體)的成員變量以下劃線結尾trailing underscore; 如:
[Add] a_local_variable, a_struct_data_member, a_class_data_member_ <<<
1
2
|
my_exciting_local_variable my_exciting_member_variable_ |
普通變量命名 Common Variable names
舉例: [下劃線會讓名字更長, 全小寫會有混淆出現: foot+ball -> football 類似]
1
2
|
string table_name; //
OK - uses underscore. string tablename; //
OK - all lowercase. |
WARNING: [why?打字麻煩?]
1
|
string tableName; //
Bad - mixed case. |
[Add]
類數據成員 Class Data Members
對於類數據成員, static和non-static的, 都和普通非成員變量一樣命名, 但是以下劃線結尾;
1
2
3
4
5
6
7
|
class TableInfo
{ ... private : string
table_name_; //
OK - underscore at end. string
tablename_; //
OK. static Pool<TableInfo>*
pool_; //
OK. }; |
<<<
結構體變量 Struct Data Members
結構體的數據成員, static和non-static的, 可以和普通變量一樣, 不用像類那樣接下劃線:
1
2
3
4
5
|
struct UrlTableProperties
{ string
name; int num_entries; static Pool<UrlTableProperties>*
pool; }; |
結構體與類的討論參考 Structs vs. Classes
全局變量 Global Variables
對全局變量沒有特別要求, 少用就好, 但如果你要用, 可以用 g_ 或其他標誌作爲前綴, 以便更好地區分局部變量;
6.5 常量命名 Constant Names
Tip 在名稱前加 k: kDaysInAWeek; 混合大小寫, 對於在全局或類內定義的常量;
爲方便閱讀, 所有編譯時常量, 無論是局部的, 全局的還是類中的, 和其他變量稍微區別一下; k後接大寫字母開頭的單詞:
1
|
const int kDaysInAWeek
= 7; |
[Add] 這個約定對於local範圍的編譯時常量來說不是強制的, 那種情況下用一般命名規則也可以;<<<
6.6 函數命名
Tip 常規函數使用大小寫混合, 取值和設置函數則要求與變量名匹配:
MyExcitingFunction(), MyExcitingMethod(), my_exciting_member_variable(), set_my_exciting_member_variable();
常規函數 Regular Functions
函數名的每個單詞首字母大寫, 沒有下劃線:
1
2
|
AddTableEntry(); DeleteUrl(); |
[Add] 如果函數會在一個error上崩潰crash, 你應該加上OrDiie, 這隻適用於會在產品代碼中使用, 而且error是在一般操作下合理發生的情況下;
1
|
OpenFileOrDie() |
取值和設值函數 Accessors and Mutators
取值和設值函數((get and set)要與存取的變量名匹配; 這兒摘錄一個類, num_entries_ 是該類的實例變量;
1
2
3
4
5
6
7
8
9
|
class MyClass
{ public : //... int num_entries() const { return num_entries_;
} void set_num_entries( int num_entries)
{ num_entries_ = num_entries; } private : int num_entries_; }; |
其他非常短小的內聯函數名也可以用小寫字母, 例如: 如果你在循環中調用這樣的函數甚至都不用緩存其返回值, 小寫命名就可以接受;
6.7 名字空間命名 Namespace Names
Tip 名字空間用小寫字母命名, 並給予項目名稱和目錄結構: google_awesome_project; [小寫是爲了和類區分?]
關於名字空間的討論和如何命名, 參考Namespaces;
6.8 枚舉命名 Enumerator Names
Tip 枚舉的命名應當和 常量 或 宏 一致: kEnumName或是 ENUM_NAME;
單獨的枚舉值應該優先採用常量的命名方式; 但宏方式的命名也可以接受; 枚舉名 UrlTableErrors(或AlternateUrlTableErrors)是類型; 所以要用大小寫混合的方式;
1
2
3
4
5
6
7
8
9
10
|
enum UrlTableErrors
{ kOK
= 0, kErrorOutOfMemory, kErrorMalformedInput, }; enum AlternateUrlTableErrors
{ OK
= 0, OUT_OF_MEMORY
= 1, MALFORMED_INPUT
= 2, }; |
2009 Jan之前我們一直建議採用宏的方式命名枚舉值; 由於枚舉值和宏之間的命名衝突collision, 直接導致了很多問題; 因此, 這裏改爲優先選擇常量風格constant-style的命名方式; 新代碼應該儘可能優先使用常量風格; 但老代碼沒必要切換到常量風格, 除非宏風格確實會產生編譯期問題;
6.9 宏命名 Macro Names
Tip 你並不打算使用宏吧? 如果一定要用, 像這樣命名: MY_MACRO_THAT_SCARES_SMALL_CHILDREN
參考 預處理宏description of macros, 通常不應該使用宏; 如果不得不用, 其命名像枚舉命名一樣全部大寫, 使用下劃線;
1
2
|
#define ROUND(x) ... #define PI_ROUNDED 3.0 |
6.10 命名規則的特例 Exceptions to Naming Rules
Tip 如果你命名的實體已有 C/C++實體相似analogous, 可參考現有命名策略convention scheme;
bigopen(): 函數名, 參照 open()的形式;
unit: typedef
bigpos: struct或 class, 參照 pos的形式;
sparse_hash_map: STL相似實體, 參照STL命名約定;
LONGLONG_MAX: 常量, 如同 INT_MAX;
---TBC---YCR