C++ Primer 学习笔记_94_用于大型程序的工具 --命名空间[续3]

用于大型程序的工具

--命名空间[续3]

六、重载与命名空间

正如我们所见,每个命名空间维持自己的作用域,因此,作为两个不同命名空间成员的函数不能互相重载。但是,给定命名空间可以包含一组重载函数成员。

1、候选函数与命名空间

命名空间对函数匹配有两个影响。一个影响是明显的:using声明或using 指示可以将函数加到候选集合。另一个影响则微妙得多。

正如前节所见,有一个或多个类类型形参的函数的名字查找包括定义每个形参类型的命名空间。这个规则还影响怎样确定候选集合,为找候选函数而查找定义形参类(以及定义其基类)的每个命名空间,将那些命名空间中任意与被调用函数名字相同的函数加入候选集合。即使这些函数在调用点不可见,也将之加入候选集合:

namespace NS
{
class Item_base
{
    //...
};

void display(const Item_base &)
{
    //...
}
}

class Bulk_item :public NS::Item_base
{
    //...
};

int main()
{
    Bulk_item book;
    display(book);  //OK
}

解释:display调用的候选函数不仅是在调用display函数的地方其声明可见的函数,还包括声明 Bulk_item类及其基类Item_base的命名空间中的函数。命名空间NS中声明 的函数display(constItem_base&) 被加到候选函数集合中。

2、重载与using声明

using声明声明一个名字。没有办法编写using声 明来引用特定函数声明:

    using NS::print(int);	//Error
    using NS::print;	//OK

如果命名空间内部的函数是重载的,那么,该函数名字的using声明声明了所有具有该名字的函数

由using声明引入的函数,重载出现using声明的作用域中的任意其他同名函数的声明。

如果using声明在已经有同名且带相同形参表的函数的作用域中引入函数,则using声明出错,否则,using定义给定名字的另一重载实例,效果是增大候选函数集合。

3、重载与using指示

using指示将命名空间成员提升到外围作用域。如果命名空间函数与命名空间所在的作用域中生命的函数同名,就将命名空间成员加载到重载集合中:

namespace libs_R_us
{
extern void print(int);
extern void print(double);
}
void print(const std::string &);

using namespace libs_R_us;

void fooBar(int val)
{
    print("Value: ");
    print(val);
}

4、跨越多个using指示的重载

如果存在许多using指示,则来自每个命名空间的名字成为候选集合的组成部分:

namespace AW
{
int print(int);
}
namespace Primer
{
double print(double);
}

using namespace AW;
using namespace Primer;

long double print(long double);

int main()
{
    print(1);	//AW::print(int)
    print(3.1);	//Primer::print(double)
}

全局作用域中print函数的重载集合包含函数print(int)、print(double)和 print(longdouble),即使这些函数原来在不同的命名空间中声明,它们都是为main中函数调用考虑的重载集合的组成部分。

//P614 习题17.22
//1
namespace primerLib
{
void compute();
void compute(const void *);
}

using primerLib::compute;

void compute(int)
{
    cout << "int" << endl;
}
void compute(double,double = 3.14);
void compute(char *,char * = 0);

int main()
{
    compute(0); //compute(int)
}

//2
namespace primerLib
{
void compute();
void compute(const void *)
{
    cout << "const void *" << endl;
}
}

void compute(int);
void compute(double,double = 3.14);
void compute(char *,char * = 0);

int main()
{
    using primerLib::compute;
    compute(0); //compute(const void *)
}

七、命名空间与模板

在命名空间内部声明模板影响着怎样声明模板特化:模板的显式特化必须在定义通用模板的命名空间中声明,否则,该特化将与它所特化的模板不同名。

有两种定义特化的方式:一种是重新打开命名空间并加入特化的定义,可以这样做是因为命名空间定义是不连续的;或者,可以用与在命名空间定义外部定义命名空间成员相同的方式来定义特化:使用由命名空间名字限定的模板名定义特化

【小心地雷】

为了提供命名空间中所定义模板的自己的特化,必须保证在包含原始模板定义的命名空间中定义特化。

C++ Primer 学习笔记_94_用于大型程序的工具 --命名空间[续3],布布扣,bubuko.com

时间: 2024-08-06 11:38:53

C++ Primer 学习笔记_94_用于大型程序的工具 --命名空间[续3]的相关文章

C++ Primer 学习笔记_93_用于大型程序的工具 --命名空间[续2]

用于大型程序的工具 --命名空间[续2] 五.类.命名空间和作用域 名字的可见性穿过任意嵌套作用域,直到引入名字的块的末尾. 对命名空间内部使用的名字的查找遵循常规C++查找规则:当查找名字的时候,通过外围作用域外查找.对命名空间内部使用的名字而言,外围作用域可能是一个或多个嵌套的命名空间,最终以全包围的全局命名空间结束.只考虑已经在使用点之前声明的名字,而该使用仍在开放的块中: namespace A { int i; namespace B { int i; int j; int f1()

C++ Primer 学习笔记_92_用于大型程序的工具 --命名空间[续1]

用于大型程序的工具 --命名空间[续1] 二.嵌套命名空间 一个嵌套命名空间即是一个嵌套作用域 -- 其作用域嵌套在包含它的命名空间内部.嵌套命名空间中的名字遵循常规规则:外围命名空间中声明的名字被嵌套命名空间中同一名字的声明所屏蔽.嵌套命名空间内部定义的名字局部于该命名空间.外围命名空间之外的代码只能通过限定名引用嵌套命名空间中的名字. 嵌套命名空间可以改进库中代码的组织: namespace cplusplus_primer { namespace QueryLib { class Quer

C++ Primer 学习笔记_89_用于大型程序的工具 --异常处理[续2]

用于大型程序的工具 --异常处理[续2] 八.自动资源释放 考虑下面函数: void f() { vector<string> v; string s; while (cin >> s) { v.push_back(s); } string *p = new string[v.size()]; //... delete p; } 在正常情况下,数组和vector都在退出函数之前被撤销,函数中最后一个语句释放数组,在函数结束时自动撤销vector. 但是,如果在函数内部发生异常,则将

C++ Primer 学习笔记_90_用于大型程序的工具 --异常处理[续3]

用于大型程序的工具 --异常处理[续3] 九.auto_ptr类[接上] 5.auto_ptr对象的复制和赋值是破坏性操作 auto_ptr和内置指针对待复制和赋值有非常关键的区别.当复制auto_ptr对象或者将它的值赋给其他auto_ptr对象的时候,将基础对象的所有权从原来的auto_ptr对象转给副本,原来的auto_ptr对象重置为未绑定状态. auto_ptr<string> strPtr1(new string("HELLO!")); auto_ptr<

C++ Primer 学习笔记_91_用于大型程序的工具 --命名空间

用于大型程序的工具 --命名空间 引言: 在一个给定作用域中定义的每个名字在该作用域中必须是唯一的,对庞大.复杂的应用程序而言,这个要求可能难以满足.这样的应用程序的全局作用域中一般有许多名字定义.由独立开发的库构成的复杂程序更有可能遇到名字冲突 -- 同样的名字既可能在我们自己的代码中使用,也可能(更常见地)在独立供应商提供的代码中使用. 库倾向于定义许多全局名字 -- 主要是模板名.类型名或函数名.在使用来自多个供应商的库编写应用程序的时候,这些名字中有一些几乎不可避免地会发生冲突,这种名字

C++ Primer 学习笔记_93_用以大型程序的工具 -命名空间[续2]

用于大型程序的工具 --命名空间[续2] 五.类.命名空间和作用域 名字的可见性穿过任意嵌套作用域,直到引入名字的块的末尾. 对命名空间内部使用的名字的查找遵循常规C++查找规则:当查找名字的时候,通过外围作用域外查找.对命名空间内部使用的名字而言,外围作用域可能是一个或多个嵌套的命名空间,最终以全包围的全局命名空间结束.只考虑已经在使用点之前声明的名字,而该使用仍在开放的块中: namespace A { int i; namespace B { int i; int j; int f1()

C++ Primer 学习笔记_88_用于大型程序的工具 --异常处理[续1]

用于大型程序的工具 --异常处理[续1] 四.又一次抛出 有可能单个catch不能全然处理一个异常.在进行了一些校正行动之后,catch可能确定该异常必须由函数调用链中更上层的函数来处理,catch能够又一次抛出将异常传递给函数调用链中更上层的函数.又一次抛出是后面不跟类型或表达式的一个throw: throw; 空throw语句将又一次抛出异常对象,它仅仅能出如今catch或从catch调用的函数中.假设在处理代码不活动时碰到空throw,就调用terminate函数. 尽管又一次抛出不指定自

C++ Primer 学习笔记_95_用于大型程序的工具 --多重继承与虚继承

用于大型程序的工具 --多重继承与虚继承 引言: 大多数应用程序使用单个基类的公用继承,但是,在某些情况下,单继承是不够用的,因为可能无法为问题域建模,或者会对模型带来不必要的复杂性. 在这些情况下,多重继承可以更直接地为应用程序建模.多重继承是从多于一个直接基类派生类的能力,多重继承的派生类继承其所有父类的属性. 一.多重继承 1.定义多个类 为了支持多重继承,扩充派生列表: class Bear : public ZooAnimal { //... }; 以支持由逗号分隔的基类列表: cla

C++ Primer 学习笔记_96_用于大型程序的工具 --多重继承与虚继承[续1]

用于大型程序的工具 --多重继承与虚继承[续1] 四.多重继承下的类作用域 成员函数中使用的名字和查找首先在函数本身进行,如果不能在本地找到名字,就继续在本类中查找,然后依次查找每个基类.在多重继承下,查找同时检察所有的基类继承子树 -- 在我们的例子中,并行查找 Endangered子树和Bear/ZooAnimal子树.如果在多个子树中找到该名字,则那个名字的使用必须显式指定使用哪个基类;否则,该名字的使用是二义性的. [小心地雷] 当一个类有多个基类的时候,通过对所有直接基类同时进行名字查