15.3 名称空间的作用域与可见性

    原则上讲名称空间的作用域是全局的,但其可见域却并非如此,而且不论使用限定符还是使用using声明语句,都要求名称空间可见。就代码15.6来说,如果将namespace B的定义放在namespace A定义之后,编译器将会指出错误。using语句同样如此,如果在using声明时,namespace尚未定义,或者说namespace已经定义,但声明的实体尚未包含在此namespace中,编译器同样会指出错误,因此,名称空间同样要先定义后使用。

    15.3.1 名称空间的定义策略

    以代码15.6为基础,假设想实现如下功能:A:dispA函数中要访问B:num,这要求B定义在A前,同时在B中增加dispB函数,其中调用A:dispA函数,这要求A定义在B之前,如此看来,上述功能似乎不太可能实现。

    实则不然,这取决于名称空间的定义策略,在前面讲过名称空间中函数的定义和实现可以分开进行,这是我们解决问题的突破口,如代码15.7所示。

    代码15.7 名称空间的定义策略DefineANamespace


    <—————————————-文件名:example1507.cpp—————————————> 01 #include<iostream> 02 using namespace std; 03 extern int num=0;//外部变量num的定义性声明 04 namespace B//创建名称空间B 05 { 06 int num=2;//B中声明的num 07 void dispB(); 08 } 09 namespace A//创建名称空间A 10 { 11 int num=1;//A中声明的num 12 void dispA() 13 { 14 int num=3; 15 cout<<"dispA函数中的num:"<<num<<endl; 16 cout<<"A中的num:"<<A:num<<endl; 17 cout<<"B中的num:"<<B:num<<endl; 18 cout<<"外部的num:"<<:num<<endl; 19 } 20 } 21 namespace B//创建名称空间B 22 { 23 void dispB() 24 { 25 A:dispA(); 26 } 27 } 28 int main() 29 { 30 A:dispA(); 31 B:dispB(); 32 return 0; 33 }

    输出结果如下所示。


    dispA函数中的num:3 A中的num:1 B中的num:2 外部的num:0 dispA函数中的num:3 A中的num:1 B中的num:2 外部的num:0

    【代码解析】代码第7行,通过将namespace B中dispB函数的原型(定义)和声明分开,使得A:disp函数中,访问B:num的操作位于B的可见域,又使得B:disp函数中,调用A:disp的操作位于A的可见域。

    名称空间中的变量等实体只能声明一次,函数实现也只能有一次,但函数原型却可多次说明,常用函数原型列表来扩展名称空间的可见域,如代码15.8所示。

    代码15.8 多文件namespace组织MultiFileNamespace


    <————————————-文件名:example1508.cpp——————————————> 01 #include<iostream> 02 using namespace std; 03 extern int num=0;//外部变量num的定义性声明 04 namespace B//创建名称空间B 05 { 06 int num=2;//B中声明的num 07 void dispB(); 08 } 09 namespace A//创建名称空间A 10 { 11 int num=1;//A中声明的num 12 void dispA() 13 { 14 int num=3; 15 cout<<"dispA函数中的num:"<<num<<endl; 16 cout<<"A中的num:"<<A:num<<endl; 17 cout<<"B中的num:"<<B:num<<endl; 18 cout<<"外部的num:"<<:num<<endl; 19 } 20 } 21 int main() 22 { 23 A:dispA(); 24 B:dispB(); 25 return 0; 26 } <———————————————-文件名:nameb.cpp——————————————> 27 namespace A 28 { 29 void dispA();//原型可以多次说明 30 } 31 namespace B//创建名称空间B 32 { 33 void dispB() 34 { 35 A:dispA(); 36 } 37 }

    输出结果如下所示。


    dispA函数中的num:3 A中的num:1 B中的num:2 外部的num:0 dispA函数中的num:3 A中的num:1 B中的num:2 外部的num:0

    【代码解析】代码第33行将B:disp函数的实现放在了另一个文件nameb.cpp中,为了实现对A:dispA的调用,B:disp函数的实现必须位于namespace A的可见域内,为此,使用了下述形式对namespace A进行了“声明”,以扩大其可见域。


    namespace A { void dispA();//原型可以多次说明 }

    因为在example1508.cpp中已经对A:dispA函数进行了实现,因此,此处的dispA只能是原型形式,但是,nameb.cpp的namespace A中可以添加其他函数的原型甚至是实现,当然也可以添加其他变量,但不能是num,否则会出现重复定义错误。

    注意

    一条指导性原则就是“函数实现只能有一次,函数原型可以多次,变量声明只能有一次”,当然,名称空间中允许函数重载。

    由于声明并不分配空间,所以const类变量可多次声明,但不管声明多少次,程序只维护该变量定义后的一个版本。