首页 > 代码库 > C++ Primer 学习笔记_93_用于大型程序的工具 --命名空间[续2]
C++ Primer 学习笔记_93_用于大型程序的工具 --命名空间[续2]
用于大型程序的工具
--命名空间[续2]
五、类、命名空间和作用域
名字的可见性穿过任意嵌套作用域,直到引入名字的块的末尾。
对命名空间内部使用的名字的查找遵循常规C++查找规则:当查找名字的时候,通过外围作用域外查找。对命名空间内部使用的名字而言,外围作用域可能是一个或多个嵌套的命名空间,最终以全包围的全局命名空间结束。只考虑已经在使用点之前声明的名字,而该使用仍在开放的块中:
namespace A { int i; namespace B { int i; int j; int f1() { int j; return i; } } int f2() { return j; //Error } int j = i; }
用非常相似的方式确定类成员定义中使用的名字,只有一个重要区别:如果名字不是局部于成员函数的,就试着在查找更外层作用域之前在类成员中确定名字。
当类包在命名空间中的时候:首先在成员中找,然后在类(包括基类)中找,再在外围作用域中找,外围作用域中的一个或多个可以是命名空间:
namespace A { int i; int k; class C1 { public: C1():i(0),j(0) {} //C1::i,C1::j int f1() { return k; //A::k } int f2() { return h; //Error } int f3(); private: int i; int j; }; int h = i; //A::i } int A::C1::f3() { return h; //A::h }
除了定义成员之外,总是向上查找作用域:名字在使用之前必须声明。
【提示】
可以从函数的限定名推断出查找名字时所检查作用域的次序,限定名以相反次序指出被查找的作用域。
限定符A::C1::f3指出了查找类作用域和命名空间作用域的相反次序,首先查找函数 f3的作用域,然后查找外围类C1的作用域。在查找包含f3定义的作用之前,最后查找命名空间A的作用域。
1、实参相关的查找与类类型形参
std::string s; getline(std::cin,s);
它给出了屏蔽命名空间规则的一个例外:
接受类类型形参(或类类型指针及引用形参)的且与类本身定义在同一命名空间中的函数(包括重载操作符),在用类类型对象(或类类型的引用及指针)作为实参的时候是可见的。
当编译器看到getline函数的使用
getline(std::cin, s);
的时候,它在当前作用域,包含调用的作用域以及定义cin的类型和 string类型的命名空间中查找匹配的函数。因此,它在命名空间std中查找并找到由string类型定义的getline函数。
函数具有类类型形参就使得函数可见,其原因在于,允许无须单独的 using声明就可以使用概念上作为类接口组成部分的非成员函数。能够使用非成员操作对操作符函数特别有用。
std::string s; cin >> s; //在有些编译器上还未实现,如g++
如果没有查找规则的这个例外,我们将必须编写下面二者之一:
using std::operator>>; std::operator>>(std::cin,s);
2、隐式友元声明与命名空间
当一个类声明友元函数的时候,函数的声明不必是可见的。如果不存在可见的声明,那么,友元声明具有将该函数或类的声明放入外围作用域的效果。如果类在命名空间内部定义,则没有另外声明的友元函数在同一命名空间中声明。
namespace A { class C { friend void f(const C &); //f成为命名空间A的一员 }; }
因为该友元接受类类型实参并与类隐式声明在同一命名空间中,所以使用它时可以无须使用显式命名空间限定符:
void f2() { A::C cobj; f(cobj); }