C++学习笔记4——名称空间
1 基本概念
声名区域:可以在其中进行声明的区域。如对于在函数外声明的全局变量,声明区域为其所在的文件,函数内部声明的变量其声明区域为函数代码块之内。
潜在作用域:从声明点开始,到其声明的结尾。变量在潜在作用域内可能被另一个同名变量隐藏,如在函数中声明的局部变量,将隐藏同一文件中声明的全局变量。
名称空间:通过定义一种新的声明区域来创建命名的名称空间。
-
一个名称空间中的名称不会与另一个名称空间中的相同名称发生冲突,程序其他部分可以使用该名称空间中声明的东西。
-
名称空间可以是全局的,也可以位于另一个名称空间内部,但不能位于代码块中。
-
名称空间是开放的,可以把名称加入到已有的名称空间中。
2 名称空间的使用
- 使用作用域解析运算符访问名称空间中的名称,如:
Jack::pail = 12.34; // 使用变量
Jill::Hill mole; // 创建一个Hill结构体变量mole
Jack::fetch(); // 调用函数
2.1 using声明
using声明使特定的标识符可用,将特定的名称添加到它所属的声明区域中。如以下代码:
namespace Jill
{
double bucket(double n) { …… }
double fetch;
struct Hill { …… };
}
char fetch;
int main()
{
using Jill::fetch;
double fetch;
cin >> fetch; // 将值读入Jill::fetch变量中
cin >> ::fetch; // 将值读入Jill全局变量中
}
main()中的using声明将fetch添加到main()的声明区域中,完成该声明后,就可以使用fetch代替Jill::fetch。而::fetch则表示使用全局变量fetch。
2.2 using编译指令
using编译指令使名称空间中所有的名称都可用,常见的例子:
#include <iostream>
using namespcae std;
使用using编译指令与使用多个using声明不同,前者更像是大量使用作用域解析运算符。如果某个名称在函数中声明了,则不能用using声明导入相同的名称。然而使用using编译指令时,将进行名称解析。如下的示例:
namespace Jill
{
double bucket(double n) { …… }
double fetch;
struct Hill { …… };
}
char fetch;
int main()
{
using namespace Jill; // 导入整个名称空间
Hill Thrill; // 新建Jill::Hill 结构体
double water = bucket(2); // 调用Jill::bucket();
double fetch; // 隐藏了Jill::fetch变量
cin >> fetch; // 将值读入局部变量fetch中
cin >> ::fetch; // 将值读入全局变量fetch中
cin >> Jill::fetch; // 将值读入Jill::fetch变量中
}
int foom()
{
Hill top; // 错误
Jill::Hill crest; // 正确
}
在main()中,Jill::fetch的作用域不是局部的,不会隐藏全局变量fetch,而局部变量double fetch将隐藏全局变量fetch与Jill::fetch。如果使用作用域解析运算符,则三个fetch变量都是可用的。
一般来说,使用using声明比使用using编译指令更安全。它只导入指定的名称,如果该名称与局部名称发生冲突,则编译器会产生报错。using编译指令导入所有名称,如果与局部发生冲突,编译器不会产生报错。名称空间的开放性可能使空间中的名称散落在多个地方,难以准确知道添加了哪些名称。
名称空间可以嵌套:
namespace elements
{
namespace fire
{
int flame;
……
}
float water;
}
以下示例展示如何使用名称空间,分为3个源文件:
namep.hpp
#ifndef NAMESP_HPP_INCLUDED
#define NAMESP_HPP_INCLUDED
#include <string>
// create the pers and debts namespace
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 sunDebts(onst Debt ar[], int n);
}
#endif // NAMESP_HPP_INCLUDED
namesp.cpp
#include <iostream>
#include "namesp.hpp"
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.lanme << ", "<<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;
}
}
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};
showDebg(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: $"<<sumDebtts(zippy, 3) << endl;
return;
}
void another(void)
{
using pers::Person;
Person collector = {"Milo", "Rightshift"};
pers::showPerson(collector);
std::cout<<std::endl;
}
运行结果: