一、标准名字空间的理解:
using namespace std;就是标准名字空间的引用,std是C++标准库中的名字空间名称。大家都知道,当我们定义了一个类,而声明对象的时候就要用到 class_name 后跟对象名称,标准名字空间也是这个用法。
其实,我们可以按照一个更为抽象包含更广的类来理解标准名字空间。#include<iostream>中的iostream正是包含在这个标准名字空间里面的一个“对象”。
namespace是为了解决C++中的名字冲突而引入的。什么是名字冲突呢?比如,在文件x.h中有个类MyClass, 在文件y.h中也有个类MyClass,而在文件z.cpp中要同时引用x.h和y.h文件。显然,按通常的方法是行不能的,那怎么办呢?引入namespace即可。
标准名字空间的用法:
我们完全可以定义自己的标准名字空间,如下例:
在x.h中的内容为
// x.h
namespace MyNamespace1
{
class MyClass
{
public:
void f();
private:
int m;
};
};
在y.h中的内容为
// y.h
namespace MyNamespace2
{
class MyClass
{
public:
void f();
private:
int m;
} ;
};
然后在z.cpp中引入x.h和y.h
// z.cpp
#include "x.h"
#include "y.h"
using namespace MyNamespace1;
using namespace MyNamespace2;
void main()
{
//声明一个文件x.h中类MyClass的实例x
MyNamespace1::MyClass x;
//声明一个文件x.h中类MyClass的实例x
MyNamespace2::MyClass y;
//调用文件x.h中的函数f
x.f();
//调用文件y.h中的函数f
y.f();
}
名字空间实质上是一个作用域。前面所述,数据成员要包含在类里面,那么做为一个作用域更大的类,要声明的话,根据需要,一般的类就可以放到标准名字空间里面。
那么,当我们声明了一个自己的标准名字空间之后,是否还可以添加包含更多的类呢?
答案是肯定的,当我们需要的时候,我们还可以按照原来的格式添加,这样,再引用的时候,在定义的标准名字空间里面就包含了所有添加的类。
二、 关于名字空间定义全局实体(global entity)
全局名字空间污染(global namespace pollution)
1、名字空间定义
namespace 开头,后面是名字空间的名字。
namespace cplusplus_primer {
class matrix {/*****/};
void inverse(matrix &);
matrix operator+(const matrix &m1,matrix &m2)
{
/******/
}
const double pi = 3.1416;
}
在名字空间cplusplus_primer中声明的类的名字是
cplusplus_primer::matrix
函数的名字是
cplusplus_primer::inverse()
常量的名字是
cplusplus_primer::pi
类,函数,常量被声明它的名字空间的名字限定修饰:
这些名字被成为限定修饰符(qualified name)
名字空间的定义不一定是连续的.例如
namespace cplusplus_primer{
class matrix {/*****/}
const double pi = 3.1416;
}
namespace cplusplus_primer{
void inverse(matrix &);
matrix operator+ (const matrix &m1,const matrix &m2)
{/********/}
}
名字空间的定义可是非连续的,这对生成一个库很有帮助,它使我们更容易将库的源代码组织成
接口和实现部分。
2、域操作符
::
用户声明的名字空间成员名自动被加上前缀,名字空间名后面加上域操作符(::),名字空间成员名
由该名字空间名进行限定修饰。
名字空间成员的声明被隐藏在其名字空间中,除非我们为编译器指定查找的声明的名字空间,否则
编译器将在当前域及嵌套包含当前域的域中查找该名字的声明。
注意!!!
域操作符也可以被用来引用全局名字空间的成员。因为全局名字空间没有名字。
::member_name
指的是全局名字空间的成员。
#include <iostream>
const int max = 65000;
const int lineLength = 12;
void fibonacci(int max)
{
if (max <2) return;
cout << "0 1";
int v1 = 0,v2=1,cur;
for (int ix=3;ix <= max;++ix)
{
cur = v1+v2;
if(cur>::max) break; //引用全局名字空间的变量;
cout << cur <<"";
v1=v2;
v2=cur;
if(ix % lineLength ==0) cout << endl;
}
}
3 、嵌套名字空间
。。。。。
4 使用名字空间成员
使用限定修饰的名字形式namespace_name::member_name来引用名字空间,毫无疑问是非常麻烦的。
using 声明,using指示符
5 名字空间别名
namespace International_Business_Machines
{/*********/}
namespace IBM = International_Business_Machines;
6、 using声明
namespace cplusplus_primer
{
namespace MatrixLib
{
class matrix {/******/};
}
}
using cplusplus::MatrixLib::matrix;
using 声明引入的名字有以下特性:
1> 它在该域中必须唯一。
2> 由外围域中声明引入的相同名字被其隐藏。
3> 它被嵌套域中的相同名字的声明隐藏。
namespace blip {
int bi = 16,bj = 15, bk = 23;
}
int bj = 0;
void mainip()
{
using blip::bi; //函数mainip()中的bi指向blip::bi
++bi; //设置blip::bi为17
using blip::bj //隐藏全局域中的bj
++bj;
int bk; //bk在局部域中声明
using blip:bk; //错误:在mainip()中重复定义bk
}
int wrongInit = bk; //错误:bk在这里不可见
7、 using 指示符
namespace blip{
int bi = 16,bj = 15, bk = 23;
}
int bj = 0;
void mainip()
{
using namespace blip;
++bi; //设置blip::bi为17;
++bj; //错误:二义性
全局bj还是blip:bj?
++::bj; // 设置全局bj为1
++blip::bj; // 设置blip::bj为16
int bk = 97; //局部bk隐藏blip:bk
++bk; //设置局部bk为98
}
当我们把一个应用程序移植到一个包装在名字空间中的新版本时,using指示符非常
有用,但是使用多个using指示符会引起全局名字空间污染问题。
用多个选择性的using声明来代替using指示符会使这个问题最小化,由多个using
声明引起的二义性的错误在声明点就能被检测到,因此建议使用using声明而不是
using指示符,以便更好地控制程序中地全局名字空间污染问题。