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:

int a; //this a is defined in global namespace
//which means, its scope is global. It exists everywhere. namespace N
{
int a; //it is defined in a non-global namespace called `N`
//outside N it doesn't exist.
}
void f()
{
int a; //its scope is the function itself.
//outside the function, a doesn't exist.
{
int a; //the curly braces defines this a's scope!
}
}
class A
{
int a; //its scope is the class itself.
//outside A, it doesn't exist.
};

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:

int a = 10;

namespace N
{
int a = 100; void f()
{
int a = 1000;
std::cout << a << std::endl; //prints 1000
std::cout << N::a << std::endl; //prints 100
std::cout << ::a << std::endl; //prints 10
}
}

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

关于namespace几点建议

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

// .h 文件
namespace mynamespace { // 所有声明都置于命名空间中
// 注意不要使用缩进
class MyClass {
public:
...
void Foo();
}; } // namespace mynamespace

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

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

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

// 在 .cc 中使用别名缩短常用的命名空间
namespace baz = ::foo::bar::baz;
// 在 .h 中使用别名缩短常用的命名空间
namespace librarian {
namespace impl { // 仅限内部使用
namespace sidetable = ::pipeline_diagnostics::sidetable;
} // namespace impl inline void my_inline_function() {
// 限制在一个函数中的命名空间别名
namespace baz = ::foo::bar::baz;
...
}
} // namespace librarian

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

匿名namespace和静态变量

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

namespace {
...
} // namespace  

局部变量

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

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

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

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

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

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

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

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

  

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. css调用字体 没装微软雅黑,用css写@font-face让其能显示微软雅黑字体

    在设计布局网页时 经常想要用一些比较好看的字体,比如微软雅黑,这个字体在近年来在网页设计中运用越来越平常, 然而所使用的字体也只有自己能看到 到别的机子上 又恢复了原来的宋体神马的. 经过一位高手的提 ...

  2. 关于新小米盒子的Recovery模式如何进入

    26日下的盒子订单,经过几经波折,终于在昨天来到了我的面前,新东西到手,难免少不了一些折腾:升级系统,安装软件等.一顿折腾之后,想完全恢复到出厂设置,给盒子清一下,想进入盒子的Recovery模式,按 ...

  3. python迭代器、生成器、装饰器之迭代器

    迭代是Python最强大的功能之一,是访问集合元素的一种方式. 一般分为可迭代对象,迭代器,可迭代对象不一定是迭代器,但迭代器一定是可迭代对象 1.可以直接作用于for循环的数据类型 第一类:集合数据 ...

  4. 【Leetcode_easy】707. Design Linked List

    problem 707. Design Linked List 参考 1. Leetcode_easy_707. Design Linked List; 完

  5. iOS-ASI异步下载图片

    异步下载图片 异步下载图片ASIHTTPRequest *requestX = [ASIHTTPRequest requestWithURL:url];                 self.re ...

  6. iOS-代理设计模式delegate和protocol

    充当代理的步骤: 首先要明确谁请别人代理,谁当别人的代理 1> 请代理三部曲: 1 写一个协议protoc,把自己不方便做的事列出来(@protocol  studentDelegate < ...

  7. Egret入门学习日记 --- 问题汇总

    问题1: 图片无法拖入到 EXML 文件的问题 在日记 第六篇 有记载:https://www.cnblogs.com/dmc-nero/p/11188975.html 位于 3.6节 内容. 问题2 ...

  8. 修改jira数据库配置

  9. 总结几个最近处理问题中使用http协议的代码

    demo1:几个不同的http请求方式总结: ----------------------------------------------------------------------------- ...

  10. Java面试 - PATH与CLASSPATH 的区别?

    PATH:操作系统提供的路径配置,用于定义所有可执行程序的路径. CLASSPATH:由JRE提供的,用于定义Java 程序解释时类加载路径.