C++匿名命名空间

当定义一个命名空间时,可以忽略这个命名空间的名称:

namespce {

char c;

int i;

double d;

}

编译器在内部会为这个命名空间生成一个唯一的名字,而且还会为这个匿名的命名空间生成一条using指令。所以上面的代码在效果上等同于:

namespace __UNIQUE_NAME_ {

char c;

int i;

double d;

}

using namespace __UNIQUE_NAME_;

在匿名命名空间中声明的名称也将被编译器转换,与编译器为这个匿名命名空间生成的唯一内部名称(即这里的__UNIQUE_NAME_)绑定在一起。还有一点很重要,就是这些名称具有internal链接属性,这和声明为static的全局名称的链接属性是相同的,即名称的作用域被限制在当前文件中,无法通过在另外的文件中使用extern声明来进行链接。如果不提倡使用全局static声明一个名称拥有internal链接属性,则匿名命名空间可以作为一种更好的达到相同效果的方法。

注意:命名空间都是具有external 连接属性的,只是匿名的命名空间产生的__UNIQUE_NAME__在别的文件中无法得到,这个唯一的名字是不可见的.

C++ 新的标准中提倡使用匿名命名空间,而不推荐使用static,因为static用在不同的地方,涵义不同,容易造成混淆.另外,static不能修饰class。

另一篇;

今天得到来自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)特性。

时间: 2024-10-19 03:31:07

C++匿名命名空间的相关文章

C++文件头,命名空间,new和delete,内联函数,引用,函数重载,构造函数和析构函数,深拷贝和浅拷贝,explict,this指针

 目  录 1       开始学习C++.............................................................................................................. 4 1.1       C++的头文件.................................................................................................

c++之命名空间namespace

1命名空间解决全局变量的冲突 1 main.h文件 2 #pragma once 3 // data命名空间的名称 4 namespace data 5 { 6 int num = 20;//外部全局变量冲突 7 } 8 9 10 main.cpp 11 #include"main.h" 12 #include<iostream> 13 using namespace std; 14 15 int num = 10; 16 17 void main() 18 { 19 co

不可或缺 Windows Native (15) - C++: 命名空间

[源码下载] 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 命名空间 示例CppNamespace.h #pragma once #include <string> using namespace std; // 定义一个命名空间,并在其中定义一个类以及声明一个函数 namespace NativeDll { class CppNamespace { public: string Demo(); public: string Demo2(); }; string

C++进阶--命名空间和关键字using

//############################################################################ /* * C++关键字:using * * 1. using指示: 将命名空间所以成员引入当前作用域 * 例子: */ using namespace std; /* 2. using声明 * a. 将一个特定命名空间成员引入当前作用域 * b. 将一个成员从基类引入当前类的作用域 * 例子: */ using std::cout; cou

【转】Header Only Library的介绍

什么是Header Only Library Header Only Library把一个库的内容完全写在头文件中,不带任何cpp文件. 这是一个巧合,决不是C++的原始设计. 第一次这么做估计是STL.在80年代末C++编译器还不支持模块分离(现在也不支持,以后估计也不会支持了), STL的作者不得不把模板的实现写在头文件中, 使得一个STL库的实现绝大部分都展示给了使用者. 第一次广泛被接受估计还是在Boost库,它不只提出使用hpp做为Header Only Library的文件后缀(因为

我的C++笔记(数据的共享与保护)

*数据的共享与保护: * 1.作用域: * 作用域是一个标识符在程序正文中有效的区域.C++中标识符的作用域有函数原型作用域.局部作用域(块作用域).类作用域和命名空间作用域. * (1).函数原型作用域: * 函数原型作用域是C++中最小的作用域,在函数原型中一定要包含形参的类型说明.在函数原型声明时形式参数的作用范围就是函数原型的作用域.如:double area(double radius);标识符radius的作用范围就在函数area形参列表的括号之间. * 由于在函数原型的形参列表中起

More Effective C++ 条款31 让函数根据一个以上的对象类型来决定如何虚化

1. 假设要编写一个发生在太空的游戏,其中有飞船(spaceship),太空站(space station)和小行星(ssteroid),使它们继承自一个抽象基类GameObject,整个继承体系像这样: class GameObject { ... }; class SpaceShip: public GameObject { ... }; class SpaceStation: public GameObject { ... }; class Asteroid: public GameObj

Google C++ Style Guide的哲学

Google C++ Style Guide并不是一个百科全书,也不是一个C++使用指南,但它描述适用于Google及其开源项目的编码指南,并不追求全面和绝对正确,也有许多人置疑它的一些规则.但作为一个最具影响力的编码规范,它里面有许多内容值得我们研究学习. 以下主要摘自GSG负责人Titus Winters在CppCon 2014上的演讲. 制订Google C++ Style Guide的目的 引导开发去做对的事,同时不易犯错. 哲学总结 关注于读者,而非作者 (Optimize for t

[Project] SpellCorrect源码详解

该Project原来的应用场景是对电商网站中输入一个错误的商品名称进行智能纠错,比如iphoae纠错为iphone.以下介绍的这个版本对其作了简化,项目源代码地址参见我的github:https://github.com/jianxinzhou/MyProject_1/tree/uint32 . 该Project的主要思想是利用字符串编辑距离来实现拼写纠错.每当客户端来一个查询词,服务器返回与其编辑距离在2以内的单词中词频最高的那个单词.以下是对该项目的简要介绍与分析,具体代码仍以github中