C++语言编程规范-作用域、模板和 C++其他特性
01
作用域
使用名字空间进行归类,避免符号冲突
说明:名字空间主要解决符号冲突问题。
示例:两个不同项目的全局作用域都有一个类 Foo, 这样在编译或运行时造成冲突。如果每个项目将
代码置于不同名字空间中
namespace project1
{
class Foo;
//…
}
namespace project2
{
class Foo;
//…
}
作为不同符号自然不会冲突:project1::Foo 和 project2::Foo。
建议名字空间的名称采用全小写,为避免冲突,可采用项目(产品部件)或目录结构。用名字空间把整个源文件封装起来,以区别于其它名字空间,但是这些内容除外:文件包含(include), 全局标识的声明/定义以及类的前置声明。
#include "a.h"
DEFINE_bool(someflag, false, “dummy flag”);
class C; //全局名字空间中类C的前置声明
namespace a{class A;} //a::A 的前置声明
//以上代码就不要放在名字空间b中。
namespace b
{
//b中的代码…
} //namespace b
02
不要在头文件中或者#include 之前使用 using 指示符
03
避免使用 using namespace std;
说明:使用 using namespace std;会将标准库的所有符号导入到这个文件,导致命名冲突,如果是在头文件使用了此条语句,后果将是不可预料的,应该引用单独的命名空间,例如 std::string。
04
尽量少使用嵌套类
说明:一个类在另一个类中定义,这样的类被称为嵌套类。嵌套类是其外围类的成员,嵌套类也被称为成员类。
class Foo
{
private:
//Bar是嵌套在Foo中的成员类
class Bar
{
//…
};
};
跟其它类一样,嵌套类可以声明为 public、priate 和 protected 属性,因此,从外部访问嵌套类,遵循类成员的访问规则。一般来说,应该尽量少用嵌套类。嵌套类最适合用来对它们的外层类实现细节建模
(如:方便实现链表、容器等算法),且在这个类需要访问外围类所有成员(包括私有成员)时才使用嵌套类。 不要通过嵌套类来进行命名分组,应该使用名字空间。
05
尽可能不使用局部类
说明:定义在函数体内的类称为局部类。局部类只在定义它的局部域内可见。局部类的成员函数必须被定义在类定义中,且不能超过 15 行代码。否则,代码将变得很难理解。
06
使用静态成员函数或名字空间内的非成员函数,避免使用全局函数
说明:非成员函数放在名字空间内可避免污染全局作用域。
如果你必须定义非成员函数, 又只是在 .cpp 文件中使用它, 也可使用 static 关键字 (如 static intFoo() {...}) 限定其作用域。
07
避免 class 类型的全局变量,尽量用单例模式
说明:静态生存周期的对象, 包括全局变量, 静态变量, 静态类成员变量, 以及函数静态变量, 都必须是原生数据类型 (POD : Plain Old Data)。
静态变量的构造函数, 析构函数以及初始化操作的调用顺序在 C++标准中未明确定义,从而导致难以发现的 bug。比如作用域结束时,某个静态变量已经被析构了,但其他代码还试图访问该变量,导致系统崩溃。所以只允许 POD 类型的静态变量。同样,不允许用函数返回值来初始化静态变量。
08
模板
09
其他
不要在 extern "C"内部使用#include 包含其他头文件
说明:在 C++代码中调用 C 的库文件,需要用 extern "C"来告诉编译器:这是一个用 C 写成的库文件,请用 C 的方式来链接它们。
严格的讲,只应该把函数、变量以及函数类型这三种对象放置于 extern "C"的内部。如果把#include指令放在 extern "C"里面,可能会导致 extern "C"嵌套而带来如下几个风险:extern "C"嵌套过
深,导致编译错误,extern "C"嵌套后,改变其他某些文件的编译链接方式。
避免使用友元
说明:友元扩大了 (但没有打破) 类的封装边界。友元会导致类间强耦合,打破封装,暴露出具体实现,从而使友元和类的实现紧耦合;友元不可继承,降低可继承性。
例外:某些情况下, 相对于将类成员声明为 public, 使用友元是更好的选择, 尤其是你只允许另一个类访问该类的私有成员时。
避免使用 RTTI
说明:RTTI(Run-Time Type Identification)允许在运行时识别对象的类型。使用 RTTI 很容易违反“开放封闭原则”。如果要根据派生类的类型来确定执行不同逻辑代码, 虚函数无疑更合适,在对象内部就可以处理类型识别问题;如果要在对象外部的代码中判断类型, 考虑使用双重分派方案, 如访问者模式,在对象本身之外确定类的类型。所以,不建议使用 RTTI,除非在一些特定场合如某些单元测试中会用到。
使用 sizeof(变量)而不是 sizeof(类型)
说明:使用 sizeof(varname),当代码中变量类型改变时会自动更新。
struct DATA data;
memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(DATA)); //当 data 改为其他类型时,出错。
另外,对数组来说,sizeof(数组变量)并不一定是元素的个数,元素个数是 sizeof(数组变量)/sizeof(数组变量[0])。
3项目组内部应统一 C++的使用标准
说明:不同的编译器支持的 C++标准都不太一致,所以为了避免这些问题,项目组内部应该根据平台事先定义好使用的 C++标准版本。