1.名字空间(Namespace)

C++ 在 C 的基础上引入了名字空间机制,使C中作用域的级别从原有的文件域(全局作用域)、函数作用域和代码块作用域(局部域)增加了名字空间域和类域。名字空间是ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突。

**优点:**命名空间提供了(可嵌套)命名轴线(name axis,注:将命名分割在丌同命名空间内),当然,类也提供了(可嵌套)的命名轴线(注:将命名分割在丌同类的作用域内)。

**缺点:**命名空间具有迷惑性,因为它们和类一样提供了额外的(可嵌套的)命名轴线。在头文件中使用不具名的空间(匿名名字空间)容易违背C++的唯一定义原则(One Definition Rule (ODR))。

使用名字空间应该坚持以下几点规范:
(1)推荐和提倡使用匿名名字空间

// .cpp文件中
namespace
{ // 命名空间的内容无需缩进enum { UNUSED, EOF, ERROR }; // 经常使用的符号 bool AtEof() { return pos_ == EOF; } // 使用本命名空间内的符号EOF
} // namespace

匿名名字空间结束时用注释// namespace标识。

使用匿名名字空间的作用主要是将匿名名字空间中的成员的作用域限制在源文件中,其作用域与使用static关键字类似,但是与static关键字不同的是:包含在匿名名字空间中的成员(变量或者函数)具有外部连接特性,而用static修饰的变量或者函数具有内部连接特性,不能用来实例化模板的非类型参数。参考如下代码:

#include <iostream>
using namespace std;template <char*p> class Example
{
public:void display() {cout<<*p<<endl;}
};static  char c='a';
int main(int argc,char* argv[])
{Example<&c> a; //编译出错a.display();
}

此程序无法通过编译,因为静态变量c不具有外部连接特性,因此不是真正的“全局”变量。而类模板的非类型参数要求是编译时常量表达式,或者是指针类型的参数要求指针指向的对象具有外部连接性。同样是上面的这个程序,将char c=’a’;至于匿名空间进行定义,即可通过编译并运行。读者可自行考证。

(2)最好不要使用using指示符来引用名字空间
使用using指示符实际上就是取消了名字空间的保护作用,增加了命名冲突的概率。考察如下程序:

#include <iostream>
using std::cout;
using std::endl;namespace FOO
{int a=1;
}int a=2;int main()
{using namespace  FOO;//引入了与a同名的变量cout<<"a:"<<a<<endl; //出现二义性return 0;
}

以上程序编译不通过,原因是使用using导入名字空间后,引入了名字空间中所有的成员,间接的取消了名字空间的保护作用,增加了同名标识符的命名冲突。如果要访问名字空间FOO中的变量a的话,真确的用法应该是使用作用域运算符::来指明a所在的作用域,即cout<<FOO::a<<endl;

(3)尽量不要使用全局函数
应该使用命名空间中的非成员函数和类的静态成员函数。这样做的原因是在某些情况下,非成员函数和静态成员函数是非常有用的,将非成员函数置于命名空间中可避免对全尿作用域的污染。

有时,不把函数限定在类的实体中是有益的,甚至需要这么做,要么作为静态成员,要么作为非成员函数。非成员函数不应依赖于外部变量,并尽量置于某个名字空间中。相比单纯为了封装若干不共享任何静态数据的静态成员函数而创建类,不如使用名字空间。

定义于同一编译单元的函数,被其他编译单元直接调用可能会引入不必要的连接依赖,静态成员函数对此尤其敏感。可以考虑提取到新类中,或者将函数置于独立的名字空间中。如果你确实需要定义非成员函数,又只是在.cpp文件中使用它,可使用匿名名字空间或static(如static int Foo() {…})限定其作用域。

2.嵌套类(Nested Class)

在一个类体中定义的类叫作嵌套类,也叫成员类(member class)。拥有嵌套类的类叫外围类,有些地方也叫被嵌套类。

class Foo
{
private: //Bar是嵌套在Foo中的成员类 class Bar{ ... };
};

优点:当嵌套(成员)类只在被嵌套类(enclosing class)中使用时很有用,将其置于被嵌套类作用域作为被嵌套类的成员不会污染其他作用域同名类。可在被嵌套类中前置声明嵌套类,在.cpp文件中定义嵌套类,避免在被嵌套类中包含嵌套类的定义,因为嵌套类的定义通常只与实现相关。

缺点:只能在被嵌套类的定义中才能前置声明嵌套类。因此,任何使用Foo::Bar*值针的头文件必须包含整个Foo的声明。

规范:不要将嵌套类定义为public,除非它们是接口的一部分,比如,某方法使用了这个类的一系列选项。

3.局部变量(Local Variable)

(1)将局部变量尽可能置于最小作用域内,在定义时将其显示初始化
C++允许在函数的任何位置声明和定义变量,我们提倡在尽可能小的作用域中定义变量,离第一次使用的位置越近越好,使得代码易于阅读、易于定位变量的定义位置、变量类型和初始值。特别的,在定义变量时应显示的初始化。

int i;
i = f();       // 坏——初始化和声明分离
int i = g();   // 好——初始化时声明

(2)构造数据类型的变量尽可能放在循环体外定义
如果变量是一个对象,每次进入作用域都要调用其构造函数,每次退出作用域都要调用其析构函数。

 // 低效的实现for (int i = 0; i < 1000000; ++i){Foo f; // 构造函数和析构函数分别调用1000000次! f.DoSomething(i);
}

类似以下变量f放到循环作用域外面声明要高效的多:

Foo f; //构造函数和析极函数只调用1次
for(int i = 0; i < 1000000; ++i)
{f.DoSomething(i);
}

4.全局变量(Global Variables)

(1)尽量不要定义构造类型的全局变量
构造类型的全局变量,如类对象的构造函数、析构函数以及初始化操作的调用顺序只是被部分规定,每次生成有可能会有发化,从而导致难以发现的bugs。

因此,应禁止使用class类型的全局变量(包括STL的string, vector等等),因为它们的初始化顺序有可能导致构造出现问题。内建类型和由内建类型构成的没有构造函数的结构体可以使用,如果一定要使用class类型的全局变量,请使用单件模式(singleton pattern)。

(2)对于全局的字符串常量,使用C风格的字符串,而不要使用STL的字符串

const char kFrogSays[] = "ribbet";

虽然允许在全局作用域中使用全局发量,使用时务必三思。大多数全局变量应该是类的静态数据成员,或者当其只在.cpp文件中使用时,将其定义到不具名名字空间中,或者使用静态关联以限制变量的作用域。

记住,静态成员变量视为作用域限制在类域的全局变量,所以,也不能是class类型!

5.小结

(1)cpp源文件中的匿名名字空间可避免命名冲突、限定作用域,避免直接使用using指示符污染命名空间;
(2)嵌套类符合局部使用原则,只是不能在其他头文件中前置定义,尽量不要设为public;
(3)尽量不用全局函数和全局变量,考虑作用域和命名空间限制,尽量单独形成编译单元;
(4)多线程中的全局变量(含静态成员变量)不要使用class类型(含STL容器),避免不明确行为导致的bugs。

作用域的使用,除了考虑名称污染、可读性之外,主要是为降低耦合度、提高编译和执行效率。


参考文献

[1] C++名字空间详解
[2] C++的作用域与生命周期
[3] 百度文库.Google C++编码规范中文版

C++ 作用域使用规范建议相关推荐

  1. Windows客户端C/C++编程规范“建议”——前言

    前言 工作中接触了很多编程规范.其中最有意思的是,公司最近发布了一版C/C++编程规范,然后我看到该规范的最后一段时,有这么一句:"该规范不适用于Windows平台开发".看来这份 ...

  2. 来自Mozilla的CSS书写规范建议

    一个来自Mozilla的CSS书写规范建议,希望对大家有帮助 引用内容 //显示属性 display list-style position float clear //自身属性 width heig ...

  3. 【转】Android编码规范建议18条

    转自:http://www.chinaz.com/design/2015/0908/443732.shtml Android编码规范建议18条 适合手机app设计师和android 工程师阅读. 1. ...

  4. 【Python】标识符 ( Python 标识符命名规则 - 强制性 | 内容限定 | 大小写敏感 | 非关键字 | Python 标识符命名规范 - 建议性 | 下划线命名法 | 英文字母全小写 )

    文章目录 一.Python 标识符 1.Python 标识符命名规则 ( 强制性 ) 2.Python 标识符命名规范 ( 建议性 ) 二.代码示例 1.内容限定代码示例 2.大小写敏感 3.非关键字 ...

  5. 蓝鲸平台MySQL数据库管理规范建议

    蓝鲸平台MySQL数据库管理规范建议 MySQL作为蓝鲸平台存取数据的主要数据库,其稳定性关系到蓝鲸平台的使用体验,而其数据安全性则可能关系到企业IT资产相关信息,在安装和维护蓝鲸平台的过程中应引起足 ...

  6. C++编码风格/规范/建议

    C++编码规范下载链接 Google 开源项目风格指南 里面包含五份(C++ .Objective-C.Python .JSON.Shell )中文版的风格指南. 如果你的类不需要拷贝 / 移动操作, ...

  7. FxCop的一些规范建议

    下面是根据FxCop整理的.NET代码编写规范,仅供参考. 一. Design(设计) 1. Abstract types should not have constructors 抽象类不应该声明构 ...

  8. 面试官:你对MySQL高性能优化有什么规范建议?

    点击上方"朱小厮的博客",选择"设为星标" 做积极的人,而不是积极废人 来源:http://suo.im/4ZxzBf 数据库命令规范 所有数据库对象名称必须使 ...

  9. 【C#语言规范】从FxCop归纳出来的一些规范建议

    下面是根据FxCop整理的.NET代码编写规范,仅供参考. 一. Design(设计) 1. Abstract types should not have constructors 抽象类不应该声明构 ...

最新文章

  1. 刚入行的小菜鸡,怎样做好功能测试?
  2. C#中Dispose和Close的区别
  3. python能开发手机程序吗_python能否开发安卓应用app?当然可以,python助你轻松搞定...
  4. redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  5. YSlow[转:大众点评]
  6. 联通eSIM卡哪些城市可以开通办理
  7. 魅族前副总裁李楠谈“苹果对5G判断”,理解万岁!
  8. 认识安全测试之SQL注入
  9. 星型模型 3nf的区别_数据库和数据仓库的区别和联系
  10. Scrum Meeting 2 (2016-12-19 Mon)
  11. 基金公司十大非货规模逆袭(2010-2020)
  12. 实现asp程序调用摄像头并控制摄像头进行拍照
  13. 计算机网络高校校园网设计思路,网络工程设计与实现程设计高校校园网设计方案.doc...
  14. 招标采购专业实务课程大纲--刘小明老师
  15. MATLAB db4小波分解与重构,语音降噪
  16. OpenStreetMap + Leaflet 当前位置定位
  17. 计算机专业师范类毕业论文,师范生毕业论文范文
  18. python hist alpha_matplotlib可视化篇hist()--直方图
  19. 各大 IT 公司的架构图
  20. Cent OS借助YUM快速安装MySQL

热门文章

  1. 1键将 Python2 代码自动转化为 Python3
  2. 帮助打造无障碍APP Google将自动化测试GTXiLib
  3. 转] 两种自定义表单设计方案
  4. Mellanox刘通:开放的理念让Mellanox的优势愈加凸显
  5. android 显示Gift图片
  6. c语言常用单词表格,C语言常用单词
  7. 【软件工程】基准配置(基线配置)
  8. Twitter高并发高可用架构
  9. 访问tomcat7 java.lang.ClassCastException: org.apache.jasper.el.ELContextImpl
  10. 上海卓道医疗完成千万级Pre-A轮融资,幂方资本领投...