1,类型名的第一个字母大写,最后以_T结尾
2,变量和函数名首字母小写,其后每一个单词的首字母大写,其它小写。
3,全大写的函数名,和小写的函数名一样,不过是增加了错误处理而已,编译时用inline实现。
4,指针用p开头或者用Ptr结尾。
5,用前缀区分作用域:i_ (instance scope)、c_ (class scope)、g_ (global scope)、f_ (file scope)。yathing:不加下划线,表示数据类型,m_ 表示成员变量,等等......
6,全大写的前缀,表示项目名、Packet或者Library等(命名空间级别以上)。
7,用可发音的名字。
8,词汇通用、通俗、但是避免误解。
9,lhs,函数左值参数;rhs,函数右值参数。
10,a、an、any区分重名参数。
11,指针和引用的区别关键:NULL是不是合法值。
12,无符号、位操作,慎用。效率低下、兼容性问题等。
13,内置数据类型传值、非内置类型传引用(首选)或指针。
14,若不得不使用参数不确定的函数,用<stdarg.h>提供的方法[1]。
15,若必须返回值,不要强行返回引用[2]。
16,禁止成员函数返回成员的引用或指针,只读的例外[3]。
17,显示禁止编译器自动生成不需要的函数[4]。
18,绝不要重新定义继承来的非虚函数。
19,绝不要重新定义缺省参数值。
20,多重继承的基类析构函数都应该是虚函数。
21,纯虚函数:只继承接口并且派生类必须提供实现。一般虚函数:继承接口并提供缺省实现。
22,类型差异不影响行为时,用模板,否则用继承。
23,谁申请谁释放[5]。
24,关于虚友元函数[6]。
25,关于虚构造函数[7]。
26,不要用构造函数初始化静态成员。
27,包含资源管理的类应自定义拷贝、赋值、析构函数。
28,拷贝构造、赋值、析构函数要么全自定义,要么全生成。
29,循环队列的问题常出现在:插入元素使得下标从MAX-1绕回0,删除元素使得下标从0绕回到MAX-1,插入头一两个元素,以及删除最后一两个元素时。如果我们将队首设在MAX-3处,可以将这些情况全覆盖住。
30,任何变量和成员函数,首选const修饰。
31,确保自定义操作符能和其它操作符混合使用[8]。
32,显式转换而不是隐式
33,自定义类提供asInt()这样的显式转换而不是隐式转换函数int operator int(void)
34,用关键字explicit防止单参数构造函数的类型转换功能[9]。
35,模板的使用如果有限制条件,一定要在注释和文档中描述清楚。
36,嵌套template的>>中间要加空格以区别operator >>
37,在循环过程中不要修改循环计数器。
38,不能用goto跳出、跳入循环体,不能用goto跳出、跳入程序块。
39,用inline代替宏函数、用typedef代替类型定义、用const常数代替宏常数
40,每一行不超过78个字符
41,case若不需要break则一定要加注释声明
42,注释完善代码,而不是重复代码(最简单的:这么做是为了什么)
43,用#if 0而不是/**/注释掉大段的代码
44,注释不能超出被注释代码所包含的内容[10],这个毛病初学者常犯——把注释当文档用了。
45,注释中避免引用容易变化的信息
46,注释下限:每5行代码至少一行注释;没听说过有上限。
47,该用volatile时一定要用[11]。
ps:本书后面还有附录代码,以示例的形式展现各条编程规范。因为时间缘故,就不作整理了吧!^_^
[1] <stdarg.h>中定义的宏提供了一种安全有效的访问参数链的方法。
[2] 相应的例子,参见《返回值和返回引用》
[3] 和Jal商量了一会儿,我们的意见是:指针的效率慢,所以尽量用引用(能够用的场合实在不算太多,类里面返回引用,最好还要加const)。但是引用实在是很容易令人犯错,算是仁者见仁、智者见智吧!
[4] 比如,声明拷贝构造函数、赋值函数,防止友元使用或者定义。
[5] 利用引用计数,每次拷贝或赋值的时候都只是将引用数加1,而在每个引用计数对象析构的时候引用计数减1,只有当引用计数为0时才调用析构函数。计算机中使用引用计数的应用很多,如:多用户打开同一个文件、内存页面的引用等。
[6] C++语法不允许(非成员的)友元函数为虚函数,不过我们可以通过编程技巧达到虚友元想达到的效果。
- /************************************************************************/
- /* 一般情况下基类和派生类都要加入友元operator<<打印输出,
- 我们这里却采用虚函数print输出(相当于完成友元功能的虚函数) */
- /************************************************************************/
- class Base_T
- {
- public:
- virtual void print(ostream&){}
- };
- class Derived :public Base_T
- {
- public:
- virtual void print(ostream&){}
- };
- //它不是任何类的友元,只需要带基类引用作为第二个参数即可。
- ostream& operator<<(ostream& output,Base_T& anObject)
- {
- anObject.print();
- }
[7] C++语法不允许构造函数为虚函数,但有时又需要这样的函数:它们能够根据不同情况构造出不同的派生类,这类函数实际起到虚构造函数的作用。参见下面的代码:
- class Base_T
- {
- public:
- //根据自身this类型,克隆出一个新对象
- virtual Base_T& clone(void);
- };
- Base_T& baseRef = aDrivedObj;
- Base_T& anotherBaseRef = aDerivedObj.clone();
[8] operator ^()被重定义后,x^y+b会被解释为x^(y+b),而不是所希望的(x^y)+b,因为编译器是按异或的优先级确定运算顺序的。
[9] 单参数构造函数的一个隐含意思是:将该参数转换成该类的一个对象。explicit则用来禁止编译器隐式调用该构造函数,以防止隐式的类型转换。
[10]
- 没必要说二叉树,此处代码不包括实现细节。
- //Search the set for the item using a binary-tree search algorithm
- bool contains(Item anItem);
- 恰当
- //Return true if the specified item is contained in the root
- bool contains(Item anItem);
[11] 关键字volatile的含义是:其所修饰的变量的值可能会发生变化(比如中断程序修改该变量),而这种变化是编译器察觉不到的。例子:
- char c = ioRegisters.input;//应该用volatile修饰ioRegisters.input
- c=ioRegisters.input;//否则编译器优化时可能删掉此句