C++——namespace
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 namespace, functions, classes 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 keywordnamespace
, 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 namespaceN
hides the namea
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 一开始就初始化
属于 if
, while
和 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的更多相关文章
- 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境
本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...
- C++ namespace
namespace, 命名空间, 用于解决命名冲突的问题. Python中的package/module, Javascript中的object, Java中的package都具有这样的功能. 如何使 ...
- C++ 之namespace常见用法
一.背景 需要使用Visual studio的C++,此篇对namespace的常用用法做个记录. 二.正文 namespace通常用来给类或者函数做个区间定义,以使编译器能准确定位到适合的类或者函数 ...
- using namespace std 和 using std::cin
相较using std::cin使用using namespace std不会使得程序的效率变低,或者稳定性降低,只是这样作会将很多的名字引入程序,使得程序员使用的名字集合变小,容易引起命名冲突. 在 ...
- Why Namespace? - 每天5分钟玩转 OpenStack(102)
上一节我们讨论了 Neutron 将虚拟 router 放置到 namespace 中实现了不同 subnet 之间的路由.今天探讨为什么要用 namespace 封装 router? 回顾一下前面的 ...
- 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 ...
- PHP 命名空间(namespace)
PHP 命名空间(namespace) PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物. 不过在PHP当中还是有着相当重要的意义 ...
- AMD and CMD are dead之Why Namespace?
缘由 当我看到_Franky兄的微博的时候: 我觉得我有必要出来详细说说KMDjs到底有什么本质上的优势了,连教主_Franky.貘吃馍香都不能理解他的好处,那么可想而知,在前端圈.或是全端圈.或是I ...
- 使用mvc时,在视图view中使用强类型视图,在web.config文件中添加命名空间namespace的引用不起作用,解决方法
这是view中的model代码: @model t_user_info 这是web.config配置文件只的代码: <namespaces> <add namespace=" ...
- C、C++: 引用、指针、实例、内存模型、namespace
// HelloWorld.cpp : Defines the entry point for the console application. // #include "stdafx.h& ...
随机推荐
- MODRD 指令 读取地址是哪儿来的
MODRD s1 s2 n 例如: MODRD K1 H2102 K2 (台达VFDM变频器) 读取变频器的主频率及输出频率,并存放于寄存器D1050,D1051指令中s2的数据地址是 ...
- opencv-windows安装教程
一.下载opencv 下载链接: https://opencv.org/releases/ 二.运行exe 运行exe(其实是解压),将压缩包解压到相应目录,如: D:\Program Files ( ...
- XMemcached的基本使用
XMemcached是memcached的一个java客户端,基于java nio,支持memcached的所有协议.本文简要介绍XMemcached的基本使用. 一.添加依赖 <depende ...
- JavaScript中的Truthy和Falsy
JavaScript中存在Truthy值和Falsy值的概念 — 除了boolean值true.false外,所有类型的JavaScript值均可用于逻辑判断,其规则如下: 1.所有的Falsy值,当 ...
- solr后台【web页面】增删改查
就是在下面这个页面操作 增加 {"id":"2", "name": "添加"} 查询 id:2 修改 {"id ...
- 三个思路解决413 Request Entity Too Large报错处理
最近一个项目当中,要求上传图片,并且限制图片大小,虽然在laravel当中已经添加了相关的表单验证来阻止文件过大的上传,然而当提交表单时,还没轮到laravel处理,nginx就先报错了.当你仔细看报 ...
- Beanshell post processor写文件
byte[] responseData = prev.getResponseData().; private String filePath = "F:/test.txt"; Bu ...
- 跟我一起学编程—《Scratch编程》第22课:颠弹力球
1. 能够熟练绘制角色和背景造型 2. 能够熟练控制角色角度.速度等 3. 能够熟练使用变量 4. 能够熟练使用循环.选择等指令控制程序 任务描述: 1. 绘制弹力小球.托板角色,背景造型. 2. 游 ...
- 修改feign解析器替换json
@Bean public Logger.Level getFeignLoggerLevel() { return Logger.Level.FULL ; } @Bean public Response ...
- hdu 5900 区间dp
题意:给你n对pair 里面有两个值,分别是key 和 val .你可以取相邻的两个pair 获得其中的val,前提是两个pair 的key 的 gcd 不为 1.当然你把相邻的两个取走了之后原本不相 ...