c++ 之 namespace

来源:互联网 发布:mac mysql 修改密码 编辑:程序博客网 时间:2024/06/05 23:50
namespace是用以管控命名冲突的一种方法。
将各种命名至于不同的namespace中即方便了管理,避免了命名冲突,也使得
逻辑上更为清晰。


1.1 namespace的定义
一个namespcae可以定义在全局作用域中(其实是一个默认的namespace,也可
以定义在其它的namespace中,但不能在其它作用域中定义。


如:
------------main.cpp---------------------
#include <iostream>
namespace A
{
int a;
}//注意namespace定义后不需要加;(分号)


namespcae B
{
int a;
namespcae C
{
int a; //在内层作用域内的名字会屏蔽外层作用域中相同的名字
}
}
using namespcae std; //using directiv(using指令) 后面解释


int main()
{
cout << a;  //error: a is noe declared in this scope
cout << A::a;  //using a in namespace A
cout << B::a;  //using a in namespace B
cout << B::C::a; //using a in namespace C 
return 0;
}
-----------------end code----------------
1.2 如上namespace中名字的使用和访问类中静态成员的方式是一样的。
关于namespace中名字定义的位置说明
一个namespace中的名字可以在两个地方定义
1.在名字直接所属namespace的内部定义
2.在包含名字所属的namespace的作用域定义
如:
--------------main.cpp-------------------
namespcae A
{
namespace B
{
void f();
void g();


void f() {} // f define here is ok
}
void B::g() {} // ok
namespace C
{
void B::g() {} // error : C dose not include B
}
}
void A::B::g() {}  // ok
--------------end code---------------------


1.3 与类的定义不同,namespace是开放的
规则: 如果一个namespace的名字不是前面已经出现过的namespace则是在
定义一个新的的namespace,否则就是对已有的同名namespace的补充。
---------------main.cpp------------------
namespace A
{
int a;
}
//now a is in A
void f(int) {}
void g() { f(A::b); }  //error b is not in A now 
namespace A
{
int b
}
//now a and b are in A
void g() { f(A::b); } //ok
----------------end code------------------
需要注意的是,同一个namespace也可以分开在不同的文件中定义




1.4 全局作用域所对应的隐式namespace(姑且给它个全局namespace的名字以方便描述)
任何在全局作用域中的声明或是定义都等价于在这个全局namespace中声明或定义
访问全局namespace的方法:


------------main.cpp-----------------------
int a
void f(int) {}
int main()
{
int a;
f(a);   //use a in main function
f(::a); //use a int global scope
}
------------end code-----------------------
如上  :: + 名字 即表示访问全局namespace中的名字


1.5 未命名的名字空间
如:
-------------main.cpp-----------------------
namespace
{
int i;
}
void f(int) {}
void g() { f(i); } //ok: i is defined in unnamed namespace
-------------end code-----------------------
需要注意的是:
在未命名的namespace中直接定义的名字都只具有静态的内部链接属性
即:
namespace
{
int i;
}
与 static int i;等同
这样未命名的namespace也就无法在多个文件中分开定义(因为每个文件都
具有唯一未命名namespace,不同文件的未命名的namespace是不同的,分
属各自的文件)


同时注意:
int i;
namespace
{
int i;
}
void f(int) {}
void g() { f(i); } //error : ambiguous
因为未命名的namespace中的名字都只能直接访问名字(无法使用::,因为
没有所属的namespace没有名字,而::+name表示访问的是全局namespace),
所以当全局命名空间中有相同的名字时,编译器将无法区分。


未命名的namespace也可以定义在namespace中
如:
namespcae A
{
namespace
{
int i;
}
}
void f(int) {}
void g() { f(A::i); } //可以这样访问


1.6 namespace 的别名
如:
namespace A
{
namespace B { ... }
}
namespace AA = A; // now AA is equal to A
namespace BB = A::B; // now BB is equal to A::B




2 using declaration and using directive
2.1 using declaration
如:
------------------main.cpp-------------------
namespace A
{
int f(int) {}
}


int main()
{
using A::f;
f(1); //use A::f
}
-----------------end code---------------------


使用using str 的效果就好像将str在当前作用域声明一样
所以,对于:
------------------main.cpp--------------------
namespcae A
{
int t;
int f(int) {}
}


int main()
{
double t;
int f(double);
using A::t;  //error , t have two different type;
//equal to extren int A::t; 
using A::f;  //ok: function overload. now in main have f(int) and f(double)
//equal to int A::f(int);
}
------------------end code---------------------
上面一个例子大致说明了using declaration的用法,但还有一些需要注意的地方
如上一例中将int A::f(int) 换成 int A::f(double) 则编译会出错,这是因为
在使用using declaration 时当前作用域已有一个和using declaration引入名字
完全一样的声明,这与c++中一般的情况不同,c++中一般重复声明是不会报错的,
需要注意。
另外可以使用using declaration的地方是:
全局或是namespace中
函数体中
类定义中(但只能使用基类的名字)
using declaration的作用范围:只在使用using declaration的作用域内有效。


2.2 using directive
using directive 要比 using declaration复杂
如:
-----------------main.cpp---------------------
namespace A
{
int i = 1;
}


void f()
{
using namespace A;
cout << i;  // use i in A
int i = 2;  // hide A::i
cout << i;  // use i which value is 2
}
-----------------end code---------------------


规则如下:
用法: using namespace namespace-name
作用: 假设使用using directive的作用域为A,namespace-name 定义在作用域B
 同时包含A 和 B 的最小作用域为C。
 则使用using directive后,在作用域A内(当然是在using directive这条
 语句以后)看来,A::i 就好像是在C中声明的一样

对照上面的规则之后,上一个例子就不难理解了。
使用using directive的作用域是f函数体, 引入的namespace定义在全局作用域
同时包含这两个作用域的最小作用域是全局作用域,故在f内看来A::i就好像是
在全局作用域声明的,自然f中的局部名字会屏蔽全局作用域中的名字。


注意 不同于using declaration , using directive不难在类定义中使用
另外看下面这个例子:
------------------main.cpp---------------------
int i;
namespace A
{
int i;
}
void g(int) {}
void f()
{
using namespcae i;
g(i); //error ambiguous
g(::i); //ok: use i in global scope
g(A::i); //ok: use i in namespace A
}
------------------end code----------------------
由上一例可知在f内看来A::i就像是在全局中声明的一样,但是此时全局中已经有了以
i为名的名字,这时不同于using declaration(正如2.1中所描述的using
declaration如果重名会直接报错,而不管你用没用使用过该名字)编译器不会报错,
但是当你直接使用i时无疑会有歧义,所以会报错,不过你可以使用全名以消除歧义。


using directive 有传递性
如:
-----------------main.cpp-----------------------
namespcae A
{
}


namespace B
{
using namespace A;
}


void f()
{
using namespace B;
//equal to:
//using namespace A;
//using namespace B;
}
----------------end code-------------------------
即如果引入的namespace内有using directive则也会将该using directive用于当前作用域


3、综合
3.1 名字查找
如:
----------------main.cpp-------------------------
int i = 1;
namespace A
{
int j = 1;
namespace B
{
int k = 1;
void g(int) {}
void f()
{
int p;
g(i); // use ::i which value is 1
g(j); // use A::j which value is 1
g(k); // use A::B::k which value is 1
g(p); // use local p
int i; 
int j;
int k;
g(i); // use local i
g(j); // use local j
g(k); // use loacl k
}
int i = 3;
int j = 2;
}
int i = 2;
}
------------------end code-----------------------
对于非成员函数名字查找的顺序是:
在当前作用域内,当前行之前查找,如果没有找到
则到包含当前作用域的最小作用域内查找(注意只是在此作用域内向上查找,如
上例中第一次调用g(i)时A::B中其实也有i的定义,但是确是要往下找才看得到),
重复向上直到找到定义或是找完而停止
对应到上一例中则是 f --> B --> A --> global


成员函数中略有不同
如:
-------------------mian.cpp----------------------
namespace A
{
int i;
int j;
int k;
int p;
namespace B
{
int j;
int k;
int p;
void g(int) {}
class C
{
void f()
{
int p;
g(p); // use loacl p
g(k); // use C::k 
g(j); // use A::B::j
g(i); // use A::i
}
int k;
int p;
};
}
}
-------------------end code-------------------
即在当前作用域中向上查找没有找到之后,会在整个(不仅仅是向上)类(包含基类)
中查找,如果还是在不到则在包含类定义的作用域中向上查找,以后同成员函数名字
查找。


3.2 函数调用时的名字查找
如:
-------------------main.cpp-------------------
std::string s;
void f()
{
getline(std::cin , s); //注意这里没有给getline加限定符
}
-------------------end code------------------
规则:
在匹配包含类类型(对象,指针或是引用)参数函数时,编译器会自动到包含
该类型基类其基类(如果有的话)的namespace中去查找匹配的函数,如果找到
就它加入候选集中。






0 0
原创粉丝点击