scope和namespace

scope就是我们常说的作用域,namespace是C++引入的一个关键字。这两种都和作用域有些微妙的联系,下面 引自Global scope vs global namespace的回答很好解释了这两个概念。

In C++, every name has its scope outside which it doesn't exist. A scope can be defined by many ways : it can be defined by namespacefunctionsclasses and just { }.

So a namespace, global or otherwise, defines a scope. The global namespace refers to using ::, and the symbols defined in this namespace are said to have global scope. A symbol, by default, exists in a global namespace, unless it is defined inside a block starts with keyword namespace, or it is a member of a class, or a local variable of a function:

  1. int a; //this a is defined in global namespace
  2. //which means, its scope is global. It exists everywhere.
  3.  
  4. namespace N
  5. {
  6. int a; //it is defined in a non-global namespace called `N`
  7. //outside N it doesn't exist.
  8. }
  9. void f()
  10. {
  11. int a; //its scope is the function itself.
  12. //outside the function, a doesn't exist.
  13. {
  14. int a; //the curly braces defines this a's scope!
  15. }
  16. }
  17. class A
  18. {
  19. int a; //its scope is the class itself.
  20. //outside A, it doesn't exist.
  21. };

Also note that a name can be hidden by inner scope defined by either namespace, function, or class. So the name a inside namespace N hides the name a in the global namspace. In the same way, the name in the function and class hides the name in the global namespace. If you face such situation, then you can use ::a to refer to the name defined in the global namespace:

  1. int a = 10;
  2.  
  3. namespace N
  4. {
  5. int a = 100;
  6.  
  7. void f()
  8. {
  9. int a = 1000;
  10. std::cout << a << std::endl; //prints 1000
  11. std::cout << N::a << std::endl; //prints 100
  12. std::cout << ::a << std::endl; //prints 10
  13. }
  14. }

我们说的global scope用符号表示的话就是::,C++中具名namespace,可以说是把global scope进行了划分。除此之外class,function,{ }都是划分scope的方式。

关于namespace几点建议

在命名空间的最后注释出命名空间的名字。

  1. // .h 文件
  2. namespace mynamespace {
  3.  
  4. // 所有声明都置于命名空间中
  5. // 注意不要使用缩进
  6. class MyClass {
  7. public:
  8. ...
  9. void Foo();
  10. };
  11.  
  12. } // namespace mynamespace

不应该使用 using 指示 引入整个命名空间的标识符号

  1. // 禁止 —— 污染命名空间
  2. using namespace foo;

头文件中不要使用namespace别名(如果在namespace内部使用可以),cc文件没有限制

  1. // 在 .cc 中使用别名缩短常用的命名空间
  2. namespace baz = ::foo::bar::baz;
  3. // 在 .h 中使用别名缩短常用的命名空间
  4. namespace librarian {
  5. namespace impl { // 仅限内部使用
  6. namespace sidetable = ::pipeline_diagnostics::sidetable;
  7. } // namespace impl
  8.  
  9. inline void my_inline_function() {
  10. // 限制在一个函数中的命名空间别名
  11. namespace baz = ::foo::bar::baz;
  12. ...
  13. }
  14. } // namespace librarian

禁止用inline namespace,inline namespace只在大型版本控制里有用。

匿名namespace和静态变量

在 .cc 文件中定义一个不需要被外部引用的变量时,可以将它们放在匿名命名空间或声明为 static 。但是不要在 .h 文件中使用匿名namespace,.h中可以使用static。匿名命名空间说白了就是文件作用域,就像 C static 声明的作用域一样,后者已经被 C++ 标准提倡弃用。匿名命名空间的声明和具名的格式相同,在最后注释上 namespace :

  1. namespace {
  2. ...
  3. } // namespace  

局部变量

C++ 允许在函数的任何位置声明变量. 我们提倡在尽可能小的作用域中声明变量, 离第一次使用越近越好. 这使得代码浏览者更容易定位变量声明的位置, 了解变量的类型和初始值. 特别是,应使用初始化的方式替代声明再赋值, 比如:

  1. int i;
  2. i = f(); // 坏——初始化和声明分离
  3. int j = g(); // 好——初始化时声明
  4. vector<int> v;
  5. v.push_back(1); // 用花括号初始化更好
  6. v.push_back(2);
  7. vector<int> v = {1, 2}; // 好——v 一开始就初始化

属于 ifwhile 和 for 语句的变量应当在这些语句中正常地声明,这样子这些变量的作用域就被限制在这些语句中了,举例而言:  

  1. while (const char* p = strchr(str, '/')) str = p + 1;

有一个例外, 如果变量是一个对象, 每次进入作用域都要调用其构造函数, 每次退出作用域都要调用其析构函数. 这会导致效率降低.

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

在循环作用域外面声明这类变量要高效的多:

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

  

C++——namespace的更多相关文章

  1. 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境

    本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  2. C++ namespace

    namespace, 命名空间, 用于解决命名冲突的问题. Python中的package/module, Javascript中的object, Java中的package都具有这样的功能. 如何使 ...

  3. C++ 之namespace常见用法

    一.背景 需要使用Visual studio的C++,此篇对namespace的常用用法做个记录. 二.正文 namespace通常用来给类或者函数做个区间定义,以使编译器能准确定位到适合的类或者函数 ...

  4. using namespace std 和 using std::cin

    相较using std::cin使用using namespace std不会使得程序的效率变低,或者稳定性降低,只是这样作会将很多的名字引入程序,使得程序员使用的名字集合变小,容易引起命名冲突. 在 ...

  5. Why Namespace? - 每天5分钟玩转 OpenStack(102)

    上一节我们讨论了 Neutron 将虚拟 router 放置到 namespace 中实现了不同 subnet 之间的路由.今天探讨为什么要用 namespace 封装 router? 回顾一下前面的 ...

  6. struts2中错误There is no Action mapped for namespace [/] and action name [] associated with context path

    1 There is no Action mapped for namespace [/] and action name [] associated with context path [/Stru ...

  7. PHP 命名空间(namespace)

    PHP 命名空间(namespace) PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物. 不过在PHP当中还是有着相当重要的意义 ...

  8. AMD and CMD are dead之Why Namespace?

    缘由 当我看到_Franky兄的微博的时候: 我觉得我有必要出来详细说说KMDjs到底有什么本质上的优势了,连教主_Franky.貘吃馍香都不能理解他的好处,那么可想而知,在前端圈.或是全端圈.或是I ...

  9. 使用mvc时,在视图view中使用强类型视图,在web.config文件中添加命名空间namespace的引用不起作用,解决方法

    这是view中的model代码: @model t_user_info 这是web.config配置文件只的代码: <namespaces> <add namespace=" ...

  10. C、C++: 引用、指针、实例、内存模型、namespace

    // HelloWorld.cpp : Defines the entry point for the console application. // #include "stdafx.h& ...

随机推荐

  1. MODRD 指令 读取地址是哪儿来的

    MODRD  s1  s2 n  例如: MODRD K1 H2102 K2    (台达VFDM变频器)   读取变频器的主频率及输出频率,并存放于寄存器D1050,D1051指令中s2的数据地址是 ...

  2. opencv-windows安装教程

    一.下载opencv 下载链接: https://opencv.org/releases/ 二.运行exe 运行exe(其实是解压),将压缩包解压到相应目录,如: D:\Program Files ( ...

  3. XMemcached的基本使用

    XMemcached是memcached的一个java客户端,基于java nio,支持memcached的所有协议.本文简要介绍XMemcached的基本使用. 一.添加依赖 <depende ...

  4. JavaScript中的Truthy和Falsy

    JavaScript中存在Truthy值和Falsy值的概念 — 除了boolean值true.false外,所有类型的JavaScript值均可用于逻辑判断,其规则如下: 1.所有的Falsy值,当 ...

  5. solr后台【web页面】增删改查

    就是在下面这个页面操作 增加 {"id":"2", "name": "添加"} 查询 id:2 修改 {"id ...

  6. 三个思路解决413 Request Entity Too Large报错处理

    最近一个项目当中,要求上传图片,并且限制图片大小,虽然在laravel当中已经添加了相关的表单验证来阻止文件过大的上传,然而当提交表单时,还没轮到laravel处理,nginx就先报错了.当你仔细看报 ...

  7. Beanshell post processor写文件

    byte[] responseData = prev.getResponseData().; private String filePath = "F:/test.txt"; Bu ...

  8. 跟我一起学编程—《Scratch编程》第22课:颠弹力球

    1. 能够熟练绘制角色和背景造型 2. 能够熟练控制角色角度.速度等 3. 能够熟练使用变量 4. 能够熟练使用循环.选择等指令控制程序 任务描述: 1. 绘制弹力小球.托板角色,背景造型. 2. 游 ...

  9. 修改feign解析器替换json

    @Bean public Logger.Level getFeignLoggerLevel() { return Logger.Level.FULL ; } @Bean public Response ...

  10. hdu 5900 区间dp

    题意:给你n对pair 里面有两个值,分别是key 和 val .你可以取相邻的两个pair 获得其中的val,前提是两个pair 的key 的 gcd 不为 1.当然你把相邻的两个取走了之后原本不相 ...