最重要的一致性规则是命名管理。命名风格快速获知名字代表的是什么东西:类型?变量?函数?常量?宏…?甚至不需要去查找类型声明。我们大脑中的模式匹配引擎可以非常可靠的处理这些命名规则。
命名规则具有一定的随意性,但相比较个人喜好命名,一致性更重要。所以不管你怎么想,规则总是规则。
函数命名,变量命名,文件命名要有描述性,少用缩写。
尽可能给有描述性的命名,别心疼空间,毕竟让代码易于新读者理解很重要。不要用只有项目开发者能理解的缩写,也不要通过砍掉几个字母来缩写单词。
下面给出一些通用原则的示例:
int PRice_count_reader; // 无缩写int num_errors; // "num"本来就很常见,可以缩写int num_dns_connections; // 人人都知道“DNS”是什么下面的命名规则尽量避免:
int n; // 莫名其妙int nerr; // 怪缩写int n_comp_conns; // 怪缩写int wgc_connections; // 只有贵团队知道这是什么东西int pc_reader; // "pc"有太多可能的解释了int cstmr_id; // 有删减若干字母文件名要全部小写,可以包含下划线(_)或者连字符(-),按照项目约定来。如果没有项目约定,则“_”更好。可以接受的文件命名:
* my_useful_class.cc* my-useful-class.cc* myusefulclass.cc* myusefulclass_test.cc // "_unittest"和"_regtest"已经弃用C++文件要以.cc
结尾(为什么不是.cpp
呢?)。头文件以.h结尾。专门插入文本的文件则以.inc
结尾,参见关于头文件的规则。
不要使用已经存在于/usr/include
下的文件名(即编译器搜索系统头文件的路径),如db.h
。
通常应尽量让文件名更加明确。http/_server/_logs.h
就比logs.h
要好。定义类时文件名一般成对出现,如foo/_bar.h
和foo/_bar.cc
,对应于类FooBar
。
内联函数必须放在.h
文件中,如果内联函数比较短, 就直接放在.h
中。
类型名称的每个单词首字母均大写,不包含下划线:MyExcitingClass
,MyExcitingEnum
。
所有类型命名——类,结构体,类型定义(typedef),枚举——均使用相同约定。例如:
// classes and structsclass UrlTable { ...class UrlTableTester { ...struct UrlTableProperties { ...// typedefstypedef hash_map<UrlTableProperties*, string> PropertiesMap;// enumsenum UrlTableErrors { ...变量名一律小写,单词之间用下划线连接。类的成员变量以下划线结尾,但结构体的就不用。例如:a_local_variable, a_struct_data_member, a_class_data_member_。
普通变量命名的举例:
string table_name; // 可以——用下划线string tablename; // 可以——全小写string tableName; // 差——混合大小写(但这似乎是java的命名规则?)类数据成员:
不管是静态的还是非静态的,类数据成员都可以和普通变量一样,弹药接下划线。class TableInfo {...private: string table_name_; // 可以——尾后加下划线 string tablename_; // 可以 static Pool<TableInfo>* pool_; // 可以};结构体变量:
不管是静态的还是非静态的,结构体数据成员都可以和普通变量一样,不用像类那样接下划线。结构体与类的讨论请参考 结构体vs. 类 一节。struct UrlTableProperties { string name; int num_entries;}全局变量:
对全局变量没有特别要求,少用就好,但如果你要用,可以用g_或其它标志作为前缀,以便更好的区分局部变量。在全局或者类里的常量名称前加k:kDaysInAWeek。且除去开头的k之外每个单词开头字母均大写。
所有编译时常量,无论是局部的,全局的还是类中的,和其他变量稍微区别一下。k后接大写字母开头的单词。这规则也适用于编译时的局部作用域常量,不过要按变量规则来命名也可以。
const int kDaysInAWeek = 7;常规函数使用大小写混合,取值和设置函数则要求与变量名匹配:MyExcitingFunction(), MyExcitingMethod(), my_exciting_member_variable(), set_my_exciting_member_variable()。
常规函数:
函数名的每个单词首字母大写,没有下划线。如果您的某函数出错时就要直接crash,那么就在函数名加上OrDie,但这函数本身必须集成在产品代码里,且平时也可能会出错。AddTableEntry()DeleteUrl()OpenFileOrDie()取值和设值函数:
取值(accessors)和设值(Mutators)函数要与存取的变量名匹配。这儿摘录一个类,num_entries_是该类的实例变量: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_;};其它非常短小的内联函数名也可以用小写字母,例如,如果你在循环中调用这样的函数甚至都不用缓存器返回值,小写命名就可以接受。名字空间用小写字母命名,并基于项目名称和目录结构:google_awesome_project。
关于名字空间的讨论和如何命名,参考 名字空间 一节。
枚举的命名应当和常量或者宏一致:kEnumName或者ENUM_NAME。
单独的枚举值应该优先蚕蛹常量的命名方式,但宏方式的命名也可以接受。枚举名UrlTableErrors(以及AlternateUrlTableErrors)是类型,所以要用大小写混合的方式。
enum UrlTableErrors { kOK = 0, kErrorOutOfMemory, kErrorMalformatedInput,};enum AlternateUrlTableErrors { OK = 0, OUT_OF_MEMORY = 1, MALFORMATED_INPUT = 2,};2009年1月之前,我们一直建议采用宏的方式命名枚举值。由于枚举值和宏之间的命名冲突,直接导致了很多问题。由此,这里改为优先选择常量风格的命名方式。新代码应该尽可能优先使用常量风格。但是老代码没必要切换到常量风格,除非宏风格确实会产生编译期问题。
你并不打算使用宏,对吧?如果你一定要用,像这样命名:MY_MACRO_THAT_SCARES_SMALL_CHILDREN。
参考预处理宏。通常不应该使用宏,如果不得不用,其命名像枚举命名一样全部大写,使用下划线:
#define ROUND(X) ...#define PI_ROUNDED 3.0如果你命名的实体与已有的C/C++实体相似,可参考现有命名策略。
bigopen(); // 函数名,参照open()的形式uint:bigpos: // struct或者class,参照pos的形式sparse_hash_map: // STL相似实体,参照STL命名约定LONGLONG_MAX: // 常量,如同INT_MAXTextQuery::TextQuery(std::string Word) : word/_(word) {}
,其中word_自然是类内私有成员。但是Google的命名规则也并不是完美的。事实上。例如在类内对于存取函数和其它函数采用不同的命名规则,会有时候令人迷惑(个人体验)。其它命名规则也有其好处。例如CGAL类库中的命名规则我觉得就有如下好处:1)类成员变量以m_XX命名,在编程时只要打出m_,编辑器就可以自动弹出所有类成员变量可供选择;2)指针变量以pXXX开始,使人一看就知道该变量是指针类型的,而Google命名规则中没有区分指针变量和非指针变量;3)类成员函数的命名中单词之间以下划线分开,让人更容易看清(Google的命名规则中,如果函数名很长,需要读者仔细去辨认单词的组成,进而推断函数的作用)。新闻热点
疑难解答
图片精选