C++编程规范 5 作用域、模板和C++其他特性
来源:互联网 发布:阿里云 代码托管 编辑:程序博客网 时间:2024/06/04 19:54
5 作用域、模板和C++其他特性
5.1 作用域
原则5.1 使用名字空间进行归类,避免符号冲突
说明:名字空间主要解决符号冲突问题。
示例:两个不同项目的全局作用域都有一个类 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
规则5.1 不要在头文件中或者#include之前使用using指示符
说明:使用using会影响后续代码,易造成符号冲突,所以不要在头文件以及源文件中的#include之前
使用using。
示例:
//头文件a.h
namespace A
{
int f(int);
}
//头文件b.h
namespace B
{
int f(int);
}
using namespace B;
void g()
{
f(1);
}
//源代码a.cpp
#include “a.h”
using namespace A;
#include “b.h”
void main()
{
g();//using namespace A在#include “b.h”之前,引发歧意:A::f,B::f调用不明确
}
建议5.1 尽量少使用嵌套类
说明:一个类在另一个类中定义,这样的类被称为嵌套类。嵌套类是其外围类的成员,嵌套类也被称
为成员类。
class Foo
{
private:
//Bar是嵌套在Foo中的成员类
class Bar
{
//…
};
};
跟其它类一样,嵌套类可以声明为public、priate和protected属性,因此,从外部访问嵌套类,遵循
类成员的访问规则。
一般来说,应该尽量少用嵌套类。嵌套类最适合用来对它们的外层类实现细节建模(如:方便实现链表、
容器等算法),且在这个类需要访问外围类所有成员(包括私有成员)时才使用嵌套类。 不要通过嵌套
类来进行命名分组,应该使用名字空间。
建议5.2 尽可能不使用局部类
说明:定义在函数体内的类称为局部类。局部类只在定义它的局部域内可见。
局部类的成员函数必须被定义在类定义中,且不能超过15行代码。否则,代码将变得很难理解。
建议5.3 使用静态成员函数或名字空间内的非成员函数,避免使用全局函数
说明:非成员函数放在名字空间内可避免污染全局作用域。
如果你必须定义非成员函数, 又只是在 .cpp 文件中使用它, 也可使用static关键字 (如 static int
Foo() {...}) 限定其作用域。
建议5.4 避免class类型的全局变量,尽量用单件模式
说明:静态生存周期的对象, 包括全局变量, 静态变量, 静态类成员变量, 以及函数静态变量, 都必
须是原生数据类型 (POD : Plain Old Data)。
静态变量的构造函数, 析构函数以及初始化操作的调用顺序在C++标准中未明确定义,从而导致难以发
现的 bug。比如作用域结束时,某个静态变量已经被析构了,但其他代码还试图访问该变量,导致系
统崩溃。所以只允许 POD 类型的静态变量。同样,不允许用函数返回值来初始化静态变量。
5.2 模板
模板可以衍生出一系列的类和函数,这是一种形式的代码复用。但要注意,这种形式的复用是源代码级
而不是目标代码级的。也就是说,对模板的每一次实例化都会产生一份新的源代码。与此相反,继承允
许复用基类的大部分目标代码。
滥用模板会造成三个后果:第一,代码规模的过度膨胀;第二,当修改模板时,很难预料是否会对原先
正常工作的代码造成不良影响;第三,很难确保模板所有可能的合法实例化都能正常工作。所以模板的
使用要仔细且有节制。
建议5.5 谨慎使用模板,只使用模板的基础特性
说明:模板对编译器的要求很高,当前对模板100%支持的编译器几乎没有,因此,使用前应作测试,
特别是涉及偏特化,模板参数等高级特性时。
模板的错误提示比较难懂,产生的错误要映射回模板后才能显示给编程者看,但映射毕竟不是错代码
本身,所以有时很难看懂,有时甚至失真,对于人员素质要求也高,增加了维护难度。
建议5.6 注意使用模板的代码膨胀
说明:模板会为每个类型产生一个实例,如果使用不当,会产生过多实例,特别是根据常量实例化时。
建议5.7 模板类型应该使用引用或指针
说明:实例化和参数传递复杂类型(结构体,对象),传值的代价很高;引用和指针可以提高效率。
建议5.8 模板如果有约束条件,请在模板定义处显式说明
说明:编译对模板的检查较弱,很难保证检察所有错误,因此进行显式说明可以减少模板使用错误。
建议5.9 两个模块之间接口中尽量不要暴露模板
说明:因为在编译器优化选项打开的情况下,其编译的符号为不确定,导致依赖。
5.3 其他
规则5.2 不要在extern "C"内部使用#include包含其他头文件
说明:在C++代码中调用C的库文件,需要用extern "C"来告诉编译器:这是一个用C写成的库文件,请
用C的方式来链接它们。
严格的讲,只应该把函数、变量以及函数类型这三种对象放置于extern "C"的内部。
如果把#include指令放在extern "C"里面,可能会导致extern "C"嵌套而带来如下几个风险:
extern "C"嵌套过深,导致编译错误
extern "C"嵌套后,改变其他某些文件的编译链接方式
建议5.10 避免使用友元
说明:友元扩大了 (但没有打破) 类的封装边界。友元会导致类间强耦合,打破封装,暴露出具体实
现,从而使友元和类的实现紧耦合;友元不可继承,降低可继承性。
例外:某些情况下, 相对于将类成员声明为public, 使用友元是更好的选择, 尤其是你只允许另一个
类访问该类的私有成员时。
建议5.11 避免使用RTTI
说明:RTTI允许在运行时识别对象的类型。使用RTTI很容易违反“开放封闭原则”。如果要根据派生
类的类型来确定执行不同逻辑代码, 虚函数无疑更合适,在对象内部就可以处理类型识别问题;如果
要在对象外部的代码中判断类型, 考虑使用双重分派方案, 如访问者模式,在对象本身之外确定类的
类型。所以,不建议使用RTTI,除非在一些特定场合如某些单元测试中会用到。
建议5.12 使用sizeof(变量)而不是sizeof(类型)
说明:使用 sizeof(varname),当代码中变量类型改变时会自动更新。
struct DATA data;
memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(DATA)); //当data改为其他类型时,出错。
另外,对数组来说,sizeof(数组变量) 并不一定是元素的个数,元素个数是sizeof(数组变
量)/sizeof(数组变量[0])。
- C++编程规范 5 作用域、模板和C++其他特性
- 第十章 高质量C编程规范其他经验
- 2.Objective -C其他特性
- c语言编程规范和范例
- c语言编程规范和范例
- c编程规范和常范错误
- c语言编程规范和范例
- C++/C编程风格规范
- C/C++编程规范
- C/C++ 编程规范
- C#.NET编程规范
- C#.NET编程规范
- c语言编程规范
- c/c++编程规范
- c编程注意规范
- C 语言编程 规范
- C/C++编程规范
- C/C++ 编程规范
- HDU 2544 最短路(各种最短路算法的实现)
- C++编程规范 3 函数
- Linux内核数据包处理流程-数据包接收(1)
- 解决tomcat启动时隐藏命令行
- C++编程规范 4 类
- C++编程规范 5 作用域、模板和C++其他特性
- ZZ 常用算法经典代码(C++版)
- 使用AES算法对文件进行加密/解密的操作(JAVA)
- C++ 6 资源分配和释放
- 一个是阆苑仙葩,一个是美玉无瑕
- C++ 编程规范 7 异常与错误处理
- C++编程规范 8 标准库
- C++编程规范 9 程序效率
- Linux内核数据包处理流程-数据包接收(2)