C++匿名命名空间
当定义一个命名空间时,可以忽略这个命名空间的名称:
今天得到来自google的老大的指点,学习了一个新的用法:匿名命名空间。
C++另外有一种匿名的命名空间,来保证生成的符号是局部的,这样对于匿名空间中的变量等,外部都是不可见的.
//test3.cpp
static void bar(){}
namespace //匿名的命名空间
{
float bar2;
int foo;
}
//test4.cpp
extern int foo;
extern void bar();
extern float bar2;
int main()
{
bar(); //外部的bar()被声明为static,这里链接不到符号.不能访问
bar2 = 0.1f; //外部的匿名空间哩,这里也不能访问.
foo = 0xFF;
return 0;
};//如果将test4的目标和test3的目标进行链接,实际上是找不到这些符号的.链接会失败.
匿名的命名空间是C++的特性,相对于C的static声明来说,可以在匿名的空间里面声明很多变量和函数,这样可以省去了对每个变量和函数添加static声明.
实质上匿名空间的功能跟static声明是一样的.
对于一个大型的C语言软件项目,给函数和全局变量起名不是一个容易的事情,因为必须考虑有没有可能与其它程序员写的代码冲突,多数的做法是对每个模块的一组函数名加个特定前缀,如HTRequest_setInternal、HTRequest_internal等。这使得程序员每次调用这些函数时都必须多输出一些字符,虽然使用现在比较优秀的IDE(Integrated Development Environment),不会给程序员的输入带来多少负责,但这些字符看起来还是有些多余。所以C++引入了namespace的概念,把一些标识符以命名空间树结构的方式组织起来,使代码看起来更优雅。而且事实证明,该特性是先进的,对于大型项目的作用是明显的,并且在后来的编程语言如Java、C#、Python都支持此类特性,只是有些叫法不同而已。
命名空间不仅可以用于组织类型(class、struct、Enum)等,还可以用于组织全局变量、全局函数等。如例程[2-1]所示,将不同模块的标识符分别组织到不同的命名空间中,从而避免标识符的冲突。
// 例程[2-1]
#include <iostream>
namespace sock{
typedef unsigned short socket_port_t;
const char* LOOPBACK_ADDR = “127.0.0.1”;
const socket_port_t DEFUALT_HTTP_PORT = 80;
}
int main( void )
{
std::cout<<”Local HTTP addr = “<<sock::LOOPBACK_ADDR
<<’:’<<sock::DEFUALT_HTTP_PORT<<std::endl;
return 0;
}
在大型的C++项目中使用命名空间比较好的项目如Google浏览器Chorme、开源C++库boost等,而没有使用命名空间的一个例子就是开源C++库ACE(The ADAPTIVE Communication Environment),它选择了在每个类型的前面加上前缀“ACE_”,使得标识符都比较长,而且看起来有点儿冗余。为使用起来方便,而且不修改ACE的源码,可以使用typedef标识符对这些标识符进行重命名,如例程[2-2]所示。请注意,不能在这里使用#define,因为宏不受命名空间的限制。
// 例程[2-2]
#include <ace/Mutex.h>
namespace ace{
typedef ACE_Mutex Mutex;
typedef ACE_Lock Lock;
}
1.1.2. 如何引用命令空间内的标识符
当引用的标识符不在当前命名空间或全局命名空间内时,有三种方式可以引用该标识符,如引用前一节新定义的ace命令空间中的Mutex类型:
// 方式一
ace::Mutex mutex;
// 方式二
using ace::Mutex;
Mutex mutex;
// 方式三
using namespace ace;
Mutex mutex;
方式一只在必要的时候通过域运算符“::”引用指定命令空间内的标识符,适用于当前编译单元引用ace内的标识符不多,而且编译单元内使用这些标识符的次数也不多的情况。
方式二只引入ace::Mutex一个标识符,如果在当前编译单元内使用ace::Mutex次数较多,而且不会与当前命名空间内的标识符冲突,建议使用这种方式。
方式三是把ace命名空间中的全部标识符都引入到当前命名空间中,此后ace所有的标识符对于当前命名空间都是可见的,这会提高标识符冲突的危险。如果当前编译单元用到ace命令空间内的标识符较多,而且不会出现标识符冲突的问题,可以使用这种方式,以减少字符的输入。
对于以上三种方式,建议优先选择第一种,这种方式最不容易产生标识符冲突,方式二次之,尽可能不用第三种试,即使是对于C++标准库也不要使用第三种方式,因为至少在Solaris系统中就有一个struct类型叫map ??,如果你引用了包含该类型的头文件就会导致命名冲突。
另外,建议不要在头文件中使用using语句引入标识符,否则这些标识符将被暴露到引用这个头文件的所有编译单元内,这样很容易使命名空间失去其作用而产生命名冲突。
对于用到的系统API,建议函数名前使用域运算符加以区别,使程序可读性更好,如:::GetLastError( ), ::getcwd( )。
注意,切忌在自定义的命名空间中引用系统头文件,如例程[2-3]所示,避免造成标识符的混乱。
// 例程[2-3]
namespace my_space{
#include <net/if.h>
}
1.1.3. 命令空间的别名
当要引用的命名空间比较长,而且想用第一种方式引用命名空间内的实体,则可以通过命名空间别名,为原来的命名空间起个简短的名字,如例程[2-4]。
// 例程[2-4]
namespace long_namespace{
void func( void ) { /* function body */ }
}
namespace ns = long_namespace;
int main( void )
{
ns::func();
return 0;
}
1.1.4. 匿名命令空间
当声明命名空间时的名称为空时,则该命名空间为匿名命名空间(unnamed namespace)。匿名的空间是C++用于替代使用static定义作用域为本编译单元的全局函数或全局变量的一种新的替代方式,匿名空间与命名的命名空间一样可以嵌套。由于匿名命名空间没有命名空间的名字,所以也无法在其它的编译单元内通过extern声明该变量,于是该变量自然也只在本编译单元内可见,如例程[2-5]。
// 例程[2-5]
#include <iostream>
using namespace std;
namespace{ int i = 256; }
namespace ns{
namespace { int i = 128; }
void func(void)
{
cout<<"ns::func :" <<endl;
cout<<"\t::i="<<::i<<endl;
cout<<"\tns::i="<<i<<endl;
}
}
int main(void )
{
cout<<::i<<endl;
cout<<"i="<<i<<endl;
cout<<"ns::i="<<ns::i<<endl;
ns::func();
return 0;
}
使用匿名空间比使用static至少有两个好处:
1) 对于一组多个标识符函数只需要使用一个匿名空间来声明,不需要多次输入static。
2) 可以嵌套。这样可以在不同命名空间中使用多个同名的标识符。
在C++的标准中也建议使用匿名命名空间间定义编译单元内部的全局变量,替代static,static关键词在此处被认为是过期的(deprecated)特性。
C++匿名命名空间的更多相关文章
- 不可或缺 Windows Native (15) - C++: 命名空间
[源码下载] 不可或缺 Windows Native (15) - C++: 命名空间 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 命名空间 示例CppNamespa ...
- c++之命名空间namespace
1命名空间解决全局变量的冲突 main.h文件 #pragma once // data命名空间的名称 namespace data { ;//外部全局变量冲突 } main.cpp #include ...
- C++进阶--命名空间和关键字using
//############################################################################ /* * C++关键字:using * * ...
- C++初阶(命名空间+缺省参数+const总结+引用总结+内联函数+auto关键字)
命名空间 概述 在C/C++中,变量.函数和后面要学到的类都是大量存在的,这些变量.函数和类的名称将都存在于全局作用域中,可能会导致很多冲突.使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲 ...
- 【转】Header Only Library的介绍
什么是Header Only Library Header Only Library把一个库的内容完全写在头文件中,不带任何cpp文件. 这是一个巧合,决不是C++的原始设计. 第一次这么做估计是ST ...
- C++入门篇一
双冒号(::)的作用:作用域运算符,全局作用域 void LOL::game1(){//在LOL命名空间下面的game1 cout << "LOL游戏开始" <& ...
- C++代码风格指南总结
C++代码风格指南 代码风格的重要性 今天我收到thougthwork笔试没过的消息, 心里确实很难受, 然后师兄说我代码写得很糟糕 细想一下, 我写代码确实是随心所欲, 并没有遵循什么规范; 所以现 ...
- [Project] SpellCorrect源码详解
该Project原来的应用场景是对电商网站中输入一个错误的商品名称进行智能纠错,比如iphoae纠错为iphone.以下介绍的这个版本对其作了简化,项目源代码地址参见我的github:https:// ...
- TICTOC: Header Only C++ Timer
感觉最近的更新频率略高啊-哈哈- 这次的带来的是一个十分简单便利的C++计时库. 项目地址:https://github.com/miaoerduo/tictoc 欢迎Start和提MR. 项目中有详 ...
随机推荐
- The Definitive Guide To Django 2 学习笔记(九) 第五章 模型 (一)数据库访问
以MySql数据库为例,先到http://dev.mysql.com/downloads/connector/python/处下载MysqlConnector for python的连接器. from ...
- 【复习】密码算法——AES
0 AES简介 1997年1月2号,美国国家标准技术研究所宣布希望征集一个安全性能更高的加密算法(AES)[3],用以取代DES.我们知道DES的密钥长度是64 bits,但实际加解密中使用的有效长度 ...
- Eqs - poj 1840(hash)
题意:对于方程:a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 ,有xi∈[-50,50], xi != 0, any i∈{1,2,3,4,5}. 现在给出a1,a2,a3, ...
- Windows下通过Composer安装Yii2
安装好大于5.4或更高版本的PHP环境并开启openssl扩展.如果是Apache服务器,加载Apache的mod_ssl模块. 下载Composer并安装. 开始->运行[或者WIN+R]-& ...
- Linux系统常用工具集
整理Linux系统下一些日常工作中常用工具,旨在提高效率: 1.截图软件Shutter 2.通讯聊天工具pidgin 3.守护进程工具daemontools 4.远程桌面服务TigerVNC 5.Ma ...
- js 代码风格(2)
Properties • 当访问属性的时候,我们使用点(.)操作符. var luke = { jedi: true, age: 28 }; // bad var isJedi = luke[' ...
- SQLAllocStmt与SQLFreeStmt
1.申请语句句柄 SQLAllocStmt函数为应用程序分配语句句柄,其格式为:RETCODE SQLAllocStmt(HDBC hdbc, HSTMT FAR * phstmt) 其中, hdbc ...
- boost数据结构tuple
boost数据结构tuple tuple(元组)定义了一个有固定数目元素的容器,其中每个元素类型可以不相同,这与其它容器有着本质的区别!vector和array虽然可以容纳很多元素,但是元素的类型必须 ...
- Oracle起步---创建临时表空间/表空间/创建用户/授权
1. 安装: 百度一下你就知道 2. sqlplus登录/sqlplus命令登录 在安装Oracle时,你需要记住设置的“全局数据库名”(默认为orcl) 和 口令,在以两种方式登录时: 用户名: s ...
- 在 App Store 三年學到的 13 件事(下)
博文转载至 http://blog.csdn.net/iunion/article/details/18959801 Steven Shen,曾經寫過一本書,也翻過一本書,開發 iOS app ...