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