C++编码规范

本文详细列举了C++编程中的若干规范和最佳实践,包括类型命名、变量和函数命名约定、指针和引用的使用、继承和多态、模板、资源管理等方面,旨在提高代码质量与可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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++语法不允许(非成员的)友元函数为虚函数,不过我们可以通过编程技巧达到虚友元想达到的效果。

  1. /************************************************************************/
  2. /* 一般情况下基类和派生类都要加入友元operator<<打印输出,
  3. 我们这里却采用虚函数print输出(相当于完成友元功能的虚函数)             */
  4. /************************************************************************/
  5. class Base_T
  6. {
  7. public:
  8.     virtual void print(ostream&){}
  9. };
  10. class Derived :public Base_T
  11. {
  12. public:
  13.     virtual void print(ostream&){}
  14. };
  15. //它不是任何类的友元,只需要带基类引用作为第二个参数即可。
  16. ostream& operator<<(ostream& output,Base_T& anObject)
  17. {
  18.     anObject.print();
  19. }

[7] C++语法不允许构造函数为虚函数,但有时又需要这样的函数:它们能够根据不同情况构造出不同的派生类,这类函数实际起到虚构造函数的作用。参见下面的代码:

  1. class Base_T
  2. {
  3. public:
  4.     //根据自身this类型,克隆出一个新对象
  5.     virtual Base_T& clone(void);
  6. };
  7. Base_T& baseRef = aDrivedObj;
  8. Base_T& anotherBaseRef = aDerivedObj.clone();

[8] operator ^()被重定义后,x^y+b会被解释为x^(y+b),而不是所希望的(x^y)+b,因为编译器是按异或的优先级确定运算顺序的。

[9] 单参数构造函数的一个隐含意思是:将该参数转换成该类的一个对象。explicit则用来禁止编译器隐式调用该构造函数,以防止隐式的类型转换。

[10]

  1. 没必要说二叉树,此处代码不包括实现细节。
  2. //Search the set for the item using a binary-tree search algorithm
  3. bool contains(Item anItem);
  4. 恰当
  5. //Return true if the specified item is contained in the root
  6. bool contains(Item anItem);

[11] 关键字volatile的含义是:其所修饰的变量的值可能会发生变化(比如中断程序修改该变量),而这种变化是编译器察觉不到的。例子:

  1. char c = ioRegisters.input;//应该用volatile修饰ioRegisters.input
  2. c=ioRegisters.input;//否则编译器优化时可能删掉此句

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值