17-名称空间示例
9.3.3 名称空间示例
现在来看一个多文件示例,该示例说明了名称空间的一些特性。该程序的第一个文件(参见程序清单9.11)是头文件,其中包含头文件中常包含的内容:常量、结构定义和函数原型。在这个例子中,这些内容被放在两个名称空间中。第一个名称空间叫作pers,其中包含Person结构的定义和两个函数的原型——一个函数用人名填充结构,另一个函数显示结构的内容;第二个名称空间叫作debts,它定义了一个结构,该结构用来存储人名和金额。该结构使用了Person结构,因此,debts名称空间使用一条using编译指令,让pers中的名称在debts名称空间可用。debts名称空间也包含一些原型。
程序清单9.11 namesp.h
// namesp.h
#include <string>
// create the pers and debts namespaces
namespace pers
{
struct Person
{
std::string fname;
std::string lname;
};
void getPerson(Person &);
void showPerson(const Person &);
}
namespace debts
{
using namespace pers;
struct Debt
{
Person name;
double amount;
};
void getDebt(Debt &);
void showDebt(const Debt &);
double sumDebts(const Debt ar[], int n);
}
第二个文件(见程序清单9.12)是源代码文件,它提供了头文件中的函数原型对应的定义。在名称空间中声明的函数名的作用域为整个名称空间,因此定义和声明必须位于同一个名称空间中。这正是名称空间的开放性发挥作用的地方。通过包含namesp.h(参见程序清单9.11)导入了原来的名称空间。然后该文件将函数定义添加入到两个名称空间中,如程序清单9.12所示。另外,文件names.cpp演示了如何使用using声明和作用域解析运算符来使名称空间std中的元素可用。
程序清单9.12 namesp.cpp
// namesp.cpp -- namespaces
#include <iostream>
#include "namesp.h"
namespace pers
{
using std::cout;
using std::cin;
void getPerson(Person & rp)
{
cout << "Enter first name: ";
cin >> rp.fname;
cout << "Enter last name: ";
cin >> rp.lname;
}
void showPerson(const Person & rp)
{
std::cout << rp.lname << ", " << rp.fname;
}
}
namespace debts
{
void getDebt(Debt & rd)
{
getPerson(rd.name);
std::cout << "Enter debt: ";
std::cin >> rd.amount;
}
void showDebt(const Debt & rd)
{
showPerson(rd.name);
std::cout <<": $" << rd.amount << std::endl;
}
double sumDebts(const Debt ar[], int n)
{
double total = 0;
for (int i = 0; i < n; i++)
total += ar[i].amount;
return total;
}
}
最后,该程序的第三个文件(参见程序清单9.13)是一个源代码文件,它使用了名称空间中声明和定义的结构和函数。程序清单9.13演示了多种使名称空间标识符可用的方法。
程序清单9.13 namessp.cpp
// usenmsp.cpp -- using namespaces
#include <iostream>
#include "namesp.h"
void other(void);
void another(void);
int main(void)
{
using debts::Debt;
using debts::showDebt;
Debt golf = { {"Benny", "Goatsniff"}, 120.0 };
showDebt(golf);
other();
another();
return 0;
}
void other(void)
{
using std::cout;
using std::endl;
using namespace debts;
Person dg = {"Doodles", "Glister"};
showPerson(dg);
cout << endl;
Debt zippy[3];
int i;
for (i = 0; i < 3; i++)
getDebt(zippy[i]);
for (i = 0; i < 3; i++)
showDebt(zippy[i]);
cout << "Total debt: $" << sumDebts(zippy, 3) << endl;
return;
}
void another(void)
{
using pers::Person;
Person collector = { "Milo", "Rightshift" };
pers::showPerson(collector);
std::cout << std::endl;
}
在程序清单9.13中,main()函数首先使用了两个using声明:
using debts::Debt; // makes the Debt structure definition available
using debts::showDebt; // makes the showDebt function available
注意,using声明只使用了名称,例如,第二个using声明没有描述showDebt的返回类型或函数特征标,而只给出了名称;因此,如果函数被重载,则一个using声明将导入所有的版本。另外,虽然Debt和showDebt都使用了Person类型,但不必导入任何Person名称,因为debt名称空间有一条包含pers名称空间的using编译指令。
接下来,other()函数采用了一种不太好的方法,即使用一条using编译指令导入整个名称空间:
using namespace debts; // make all debts and pers names available to other()
由于debts中的using编译指令导入了pers名称空间,因此other()函数可以使用Person类型和showPerson()函数。
最后,another()函数使用using声明和作用域解析运算符来访问具体的名称:
using pers::Person;;
pers::showPerson(collector);
下面是程序清单9.11~程序清单9.13组成的程序的运行情况:
Goatsniff, Benny: $120
Glister, Doodles
Enter first name: Arabella
Enter last name: Binx
Enter debt: 100
Enter first name: Cleve
Enter last name: Delaproux
Enter debt: 120
Enter first name: Eddie
Enter last name: Fiotox
Enter debt: 200
Binx, Arabella: $100
Delaproux, Cleve: $120
Fiotox, Eddie: $200
Total debt: $420
Rightshift, Milo