您的位置:首页 > 编程语言 > C语言/C++

C++ primer 十一 名祢空间

2016-12-17 21:27 190 查看
        在C++中,名称可以是变景、函数、结构、枚举、类以及类和结构的成员。当随着项目的增大,名称相互冲突的可能性也将增加。使用多个厂商的类库时,可能导致名称冲突。例如,两个库可能都定义了名 为List、Tree和Node的类,但定义的方式不兼容。用户可能希望使用一个库的List类,而使用另一个库 的Tree类。这种冲突被称为名称空间问题。

        C++标准提供了名称空间工具,以便更好地控制名称的作用域。经过了一段时间后,编译器才支持名称空间,但现在这种支持很普遍。

传统的C++名称空间

        第一个需要知道的术语是声明区域(declaration region)。声明区域是可以在其中进行声明的区域。例如,可以在函数外面声明全局变量,对于这种变量,其声明区域为其声明所在的文件。对于在函数中声明的变鷇,其声明区域为其声明所在的代码块。

        第二个需要知道的术语是潜在作用域(potential scope)。变量的潜在作用域从声明点开始,到其声明区域的结尾。因此潜在作用域比声明区域小,这是由于变量必须定义后才能使用。

        然而,变量并非在其潜在作用域内的任何位置都是可见的。例如,它可能被另一个在嵌套声明区域中声明的同名变最隐藏。例如,在函数中声明的局部变蛩(对于这种变量,声明区域为整个函数)将隐藏在同一个文件中声明的全局变景(对于这种变量,声明区域为整个文件)。变量对程序而言可见的范围被称为作用域(scope),前面正是以这种方式使用该术语的。图对术语声明区域、潜在作用域和作用 域进行了说明。

        C++关于全局变最和屌部变里的规则定义了一种名称空间层次^每个声明医域都可以声明名称,这些 名称独立于在其他声明区域中声明的名称。在一个阐数中声明的局部变量不会与在另一个函数中声明的尙 部变摄发生冲突。



                                                   声明区域



                                       潜在作用域和作用域

新的名称空间特性

        C++新增了这样一种功能,即通过定义一种新的声明区域来创建命名的名称空时,这样做的目的之一是提供一个声明称的区域。一个名称空间中的名称不会与另外一个名称空间的相同名称发生冲突,同时允许程序的其他部分使州该名称空间中声明的东西。例如,下面的代码使用新的关键字namespace创建了两个名称空间:Jack和Jill。

namespace Jack {

double pail; 

void fetch(); 

int pal;

struct Well {…};

}

namespace Jill {

double bucket(double n) {};

double fetch; 

int pal;

struct Hill { ... };

}

       名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。因此,在默认情况下, 在名称空间中声明的名称的链接性为外部的(除非它引用了常量)。

        除了用户定义的名称空间外,还存在另一个名称空间——全局名称空间(global namespace)。它对应于文件级声明区域,因此前面所说的全局变最现在被描述为位于全局名称空间中。

       任何名称空间中的名称都不会与其他名称空间中的名称发生冲突。因此,Jack中的fetch可以与Jill 中的fetch共存,Jill中的Hill可以与外部Hill共存。名称空间中的声明和定义规则同全局声明和定义规则相同。

       名称空间是开放的(open),即可以把名称加入到已有的名称空间中。例如,下面这条语句将名称goose 添加到Jill中己有的名称列表中:

namespace Jill {

char * goose(const char *);

}

当然,需要有一种方法来访问给定名称空间中的名称。最简单的方法是,通过作用域解柝运算符::,使用名称空间来限定该名称:

Jack::pail = 12.34; //use a variable

Jill::Hill mole;           // create a type Hill structure

Jack::fetch();           // use a function

名称空间示例

        现在来看一个多文件示例,该示例说明了名称空间的一些特性。该程序的第一个文件是头文件,其中包含头文件中常包含的内容:常虽、结构定义和函数原。在这个例子中,这些内容被放在两个名称空间中。第一个名称空间叫做pers,其中包含Person结构的定义和两个函数的原型—— 一个函数用人名填充结构,另一个函数显示结构的内容:第二个名称空间叫做debts,它定义了一个结构, 该结构用来存储人名和金额。该结构使用了Person结构,因此,debts名称空间使用一条using编译指令.
让pers中的名称在debts名称空间可用。debts名称空间也包含一些原型。

namesp.h文件:

#include<string>

namespace pers

{
struct Person
{
std::string fname;
std::string lname;
};
void getperson(Person &a);
void showperson(const Person &);

}

namespace debts

{
using namespace pers;
struct Debt
{
Person name;
double amount;
};
void getDebt(Debt &);
void showDebt(const Debt &);
double sumDebt(const Debt ar[],int n);

}

       第二个文件是源代码文件,它提供了头文件屮的函数原型对应的定义。在名称空间中声明的函数名的作用域为整个名称空间,因此定义和声明必须位于同一个名称空间中。这正是名称空间的开放性发挥作用的地方。通过包含namesp.h导入原来的名称空间。然后该文件将函数定义添加入到两个名称空间中。

namesp.cpp文件:

#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 sumDebt(const Debt ar[],int n)
{
double total=0;
for(int i=0;i<n;i++)
{
total+=ar[i].amount;
}
return total;
}

}

       最后,该程序的第三个文件是一个源代码文件,它使用了名称空间中声明和定义的结构和函数。程序演示了多种使名称空间标识符可用的方法。

namessp.cpp文件:

#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:$"<<sumDebt(zippy,3)<<endl;
return ;

}

void another(void)

{
using pers::Person;
Person collector={"milo","rightshift"};
pers::showperson(collector);
std::cout<<std::endl;

}

运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: