1、头文件c++
1. #define的保护:全部头文件都应该使用#define防止头文件被多重包含(multiple inclusion),命名格式:程序员
<PROJECT>_<PATH>_<FILE>_H_windows
为保证惟一性,头文件的命名应基于其所在项目源代码树的全路径。 数组
2.头文件依赖:使用前置声明(forward declarations)尽可能减小.h文件中#include的数量。避免多米诺骨牌效应安全
e.g.头文件中用到类File,但不须要访问File的声明,则头文件只需前置声明class File;无需#include "file/bash/file.h"。bash
在头文件中如何作到使用类Foo而无需访问类的定义?多线程
1)将数据成员类型声明为Foo* 或Foo &;函数
2)参数、返回值类型为Foo的函数只是声明(但不定义实现);单元测试
3)静态数据成员的类型能够被声明为Foo,由于静态数据成员的定义在类定义以外。测试
有时,使用指针成员替代对象成员的确更有意义,然而,这样的作法会下降代码可读性及执行效率。若是仅仅为了少包含头文件,仍是不要这样代替的好。
3.内联函数:只有当函数只有10行甚至更少时才将其定义为内联函数。对于析构函数应慎重对待,析构函数每每比其表面看起来要长,由于有一些隐式成员和基类析构函数(若是有的话)被调用!另外内联那些包含循环或switch语句的函数是得不偿失的,除非在大多数状况下,这些循环语言从不执行。复杂的内联函数的定义,应放在后缀为-inl.h的头文件中。
4.函数参数的顺序:输入参数在前,输出参数在后(输入和输出)。输入参数使用值传递或者常数引用传递,输出参数使用很是数指针传递。
5.包含文件的名称和次序:C库、C++库、其余库的.h、项目内的.h。避免隐藏依赖。
2、做用域
1.命名空间:在.cc文件中,提倡使用不具名的命名空间,使用具名命名空间时,其名称可基于项目或路径名称,不需使用using指示符。
2.嵌套类:当公开嵌套类做为接口的一部分时,虽然能够直接将他们保持在全局做用域中,但将嵌套类的声明置于命名空间时更好的选择。只能在被嵌套类的定义中才能前置声明嵌套类。不要将嵌套类定义为public,除非它们是接口的一部分。
3.非成员函数、静态成员函数和全局函数:使用命名空间中的非成员函数或静态成员函数,尽可能不要使用全局函数。
1)非成员函数不该依赖于外部变量,并尽可能置于某个命名空间中。相比单纯为了封装若干不共享任何静态数据的静态成员函数而建立类,不如使用命名空间。
2)定义于同一编译单元的函数,被其余编译单元直接调用可能会引入没必要要的耦合和链接依赖;静态成员函数对此尤为敏感,能够考虑提取到新类中,或者将函数置于独立库的命名空间中。
3)若是确实须要定义非成员函数,又只是在.cc文件中使用它,可以使用不具有命名空间或static关联限制其做用域。
4.局部变量:将函数变量尽量置于最小做用域内,在声明变量时将其初始化。
5.全局变量:class类型的全局变量时被禁止的,内建类型的全局变量是容许的,固然多线程代码中很是数全局变量也是被禁止的,永远不要使用函数返回值初始化全局变量。
1)若是必定要使用class类型的全局变量,请使用单件模式
2)对于全局的字符串常量,使用C风格的字符串,而不要使用STL的字符串;
3)静态成员变量视做全局变量,因此,也不能是class类型!
总结:做用域的使用,除了考虑名称污染、可读性以外,主要是为下降耦合度,提升编译、执行效率。
3、类
1.不在构造函数中作太多逻辑相关的初始化,可能的话使用Init()方法集中初始化有意义的数据。
在构造函数中执行操做引发的问题有:
1)构造函数中不易报告错误,不能使用异常。
2)操做失败会形成对象初始化失败,引发不肯定状态。
3)构造函数内调用虚函数,调用不会派发到子类实现中,即便当前没有子类化实现,未来还是隐患。
4)若是有人建立该类型的全局变量(虽然违背了上节提到的规则),构造函数将在main()以前被调用,有可能破坏构造函数中暗含的假设条件。
2.编译器提供的默认构造函数不会对变量进行初始化,若是定义了其余构造函数,编译器再也不提供,须要编码者自行提供默认构造函数;
3.为避免隐式转换,需将单参数构造函数声明为explicit(明确的);例外,在少数状况下,拷贝构造函数能够不声明为explicit;特地做为其余类的透明包装器的类。
4.为避免拷贝构造函数,赋值操做的滥用和编译器自动生成,可目前声明其为private且无需实现;仅在代码中须要拷贝一个类对象的时候使用拷贝构造函数,不须要拷贝时应使用DISALLOW_COPY_AND_ASSIGN。
5.仅在做为数据集合时使用struct;
6.组合>实现继承>接口继承>私有继承,子类重载的虚函数也要声明virtual关键字,虽然编译器容许不这样作;
7.避免使用多重继承,使用时,除一个基类含有实现外,其余积累均为纯接口;
8.接口类类名为Interface为后缀,除提供带实现的虚析构函数、静态成员函数外,其余均为纯虚函数,不定义非静态数据成员,不提供构造函数,提供的话,声明为protected;
9.为下降复杂性,尽可能不重复操做符,模板、标准类中使用时提供文档说明;
10.存取函数通常内联在头文件中;
11.声明次序:public->protected->private;
12.函数体尽可能短小、紧凑、功能单一。
4、C++特性
1.对于智能指针,安全第1、方便第二,尽量局部化;
2.引用形参加上const,不然使用指针形参;
3.函数重载的使用要清晰、易读;
4.鉴于容易误用,禁止使用缺省函数参数(值得商榷);
5.禁止使用变长数组;
6.合理使用友元;
7.为了方便代码管理,禁止使用异常(值得商榷);
8.禁止使用RTTI,不然从新设计代码;
9.使用c++风格的类型转换,除单元测试外不要使用dynami_cast;
10.使用流还printf+read/write,it is a problem;
11.能用前置自增/减,不用后置自增/减;
12.const能用则用,提倡const在前;
13.使用肯定大小的类型,除位组外不要使用无符号型;
14.格式化输出及结构对齐时,注意32位和64位的系统差别;
15.除字符串化、链接外尽可能避免使用宏;
16.整数用0,实数用0.0,指针用NULL,字符(串)用'\0';
17.用sizeof(varname)代替sizeof(type);
18.只使用Boost中被承认的库。
5、命名规则
1.整体规则:不要随意缩写。除函数名可适当为动词外,其余命名尽可能使用清晰易懂的名词;
2.宏、枚举等使用所有大写+下划线;
3.变量(含类、结构体成员变量)、文件、命名空间、存取函数等使用所有小写+下划线,类成员变量如下划线结尾,全局变量以g_开头;
4.普通函数、类型(含类与结构体、枚举类型)、常量等使用大小写混合,不含下划线;
5.参考现有或相近命名约定。
6、注释
1.关于注释风格,不少c++程序员更喜欢行注释,c程序员或者对块注释依然情有独钟,或者在文件头大段大段的注释时使用块注释;
2.TODO;
3.适当的缩进;
7、格式
1.行宽原则上不超过80列;
2.尽可能不使用非ASCII字符,若是使用的话,参考UTF-8格式(尤为是UNIX/LINUX下,Windows下能够考虑宽字符),尽可能不将字符串常量耦合到代码中,好比独立出资源文件,这不只仅是风格问题了;
3.UNIX/LINUX下无条件使用空格,MSVC的话使用Tab也无可厚非;
4.函数参数、逻辑条件、初始化列表;要么全部参数和函数名放在同一行,要么全部参数并排分行;
5.除函数定义的左大括号能够置于行首外,包括函数/类/结构体/枚举声明、各类语句的左大括号置于行尾,全部右大括号独立成行;
6../->操做符先后不留空格,*/&不要先后都留,一个就可,靠左靠右依各人喜爱;
7.预处理指令/命名空间不适用额外缩进,类/结构体/枚举/函数/语句使用缩进;
8.初始化用=仍是()依我的喜爱,统一就好;
9.return不要加();
10.水平/垂直留白不要滥用,怎么易读怎么来。
8、规则之例外
1.windows代码
1)不要使用匈牙利命名法,使用Google命名规则,包括对源文件使用.cc扩展名;
2)Windows定义了不少原有内建类型的同义词,如DWORD、HANDLE等等,在调用Windows API时这是彻底能够接受甚至鼓励的,但仍是尽可能使用原来的C++类型,例如,使用const TCHAR *而不是LPCTSTR;
3)使用Microsoft Visual C++进行编译时,将警告级别设置为3或更高,并将全部warnings当作errors处理;
4)不要使用#pragma once;做为包含保护,使用C++标准包含保护,包含保护的文件路径包含到项目树顶层;
5)除非万不得已,不然不使用任何不标准的扩展,如#pragma和_declspec,容许使用_ _declspec(dllimport)和_ _declspec(dllexport),但必须经过DLLIMPORT和DLLEXPORT等宏,以便其余人在共享使用这些代码时容易放弃这些扩展。
在windows上,只有不多一些偶尔能够不遵照的规则:
1)一般咱们禁止使用多重继承,但在使用COM和ATL/WTL类时可使用多重继承,为了执行COM或ATL/WTL类及其接口时可使用多重实现继承;
2)虽然代码中不该使用异常,但在ATL和部分STLl(包括Visula C++的STL)中异常被普遍使用,使用ATL时,应定义_ATL_NO_EXCEPTIONS以屏蔽异常,你要研究一下是否也屏蔽掉STL的异常,若是不屏蔽,开启编译器异常也能够,注意这只是为了编译STL,本身仍然不要写含异常处理的代码;
3)一般每一个项目的每一个源文件中都包含一个名为StdAfx.h或precompile.h的头文件方便头文件预编译,为了使代码方便与其余项目共享,避免显式包含此文件(precompile.cc除外),使用编译器选项/F1以自动包含;
4)一般名为resource.h,且只包含宏的资源头文件,没必要拘泥于此风格指南。