时间:2014.07.01
地点:基地
-----------------------------------------------------------------------------------------
命名空间对函数匹配的影响主要表现在:使用using声明或using指示能将某些函数添加到候选函数集(不同版本)中。
一、与实参相关的查找与重载
对于接受类类型实参的函数而言,其名字查找是在实参的类所在的命名空间中进行。我们将在实参类以及实参类的基类所属的命名空间中搜寻候选函数。这些命名空间中所有与被调函数同名的函数都将被添加到候选集中,即使其中某些函数在调用语句处不可见。比如:
namespace NS { class Quote{/*......*/}; void Display(const Quote&){/*......*/} }
在命名空间NS下,我们定义了一个Quote类和Display函数,该函数接受Quote类类型的参数。
class BulkItem:public NS::Quote { /*......*/ };
类BulkItem继承命名空间NS下的类Quote
int main() { BulkItem book1; Display(book1); return 0; }
在这里,我们传递给Display的实参是一个类类型BulkItem,于是调用语句的候选函数查找不仅会在调用语句所在的作用域即main()函数中查找,它还会在BulkItem已经其基类Quote所属的命名空间中查找。即在这里表现为命名空间NS中声明的函数Display(const Quote&)也将被添加到候选函数集当中。从而在这里可以正确地调用到Display函数。
-----------------------------------------------------------------------------------------
二、重载与using声明
using声明语句声明的只是一个名字,而不是一个特定的函数。比如:
using NS::print(int); //这样会编译错误,因为using不能声明特定函数 using NS::print; //正确,using在这里只声明一个名字
这样之后,该函数的所有版本都将被引入到当前作用域之中。
using声明语句引入的函数将重载该声明语句所属作用域中已有的其他同名函数(即只要条件符合,using声明语句引入的函数与该声明语句所在作用域中的其它同名函数会构成重载关系)。比如当using语句声明出现在局部作用域中时,则引入的名字将隐藏外层作用域的相关声明,与本作用域中的同名函数重载。但另一方面,如果using声明所在的作用域中已经有一个函数与新引入的函数同名且形参列表相同,则该using声明将引发错误。
-----------------------------------------------------------------------------------------
三、重载与using指示
using指示可将命名空间的成员提升到外层作用域中,如果命名空间的某个函数与该命名空间所属作用域的函数同名,则命名空间中函数将被添加到重载集合中。比如:
namespace my_space { extern void print(int); extern void print(double); } //接下来是一个普通的函数声明 void print(const std::string&); //using指示,它将把该命名空间名字提升到外层作用域,并与外层作用域同名不同参的函数重载,比如在这里using指示把名字添加到print调用的候选函数集中 using namespace myspace; //于是现在掉用print函数时有如下候选函数版本 //myspace中的print(int) //myspace中的print(double) //当前域中显式声明的print(const std::string&) void FooBar(int ival) { print("Value: "); //该句会调用全局函数的print(const string&) print(ival); //调用命名空间中的print(int) }
注意using声明与using指示的区别:
using声明仅仅是声明命名空间中存在的名字,把该命名空间中的所有该名字的函数版本或该名字变量引入到当前作用域中。而using指示时把命名空间中的所有成员都提升到外层作用域之中。而且,对于using指示而言,引入一个与已有函数函数名和形参列表全部都相同的函数时也并不会产生错误。此时,只需要指明要调用的版本是命名空间中的版本还是当前作用域的版本即可。
-----------------------------------------------------------------------------------------
四、多using指示与重载
若是存在多个using指示,则来自每个命名空间的名字都会成为候选函数集的一部分。比如:
namespace SpaceOne { int print(int); } namespace SpaceTwo { double print(double); } //使用using指示从不同的命名空间中创建一个重载函数集合 using namespace SpaceOne; using namespace SpaceTwo; //还在当前域中定义一个同名不同参函数 long double print(long double); int main() { print(1); //调用SpaceOne中的print(int) print(2.1); //调用SpaceTwo中的print(double) return 0; }
在上面,全局作用域中,函数print的重载集合中包括print(int),print(double)和print(long double),尽管它们的声明位于不同作用域中,但他们都属于mian函数中print调用的候选函数集。
重载与命名空间(学习笔记)