🌼名字冲突问题
在实际生活中,一个大型的项目往往不是一个人独立完成的,而是由若干个人合作完成的,不同的人分别完成不同的部分,最后组合成一个完整的程序。
假如不同的人分别定义了类,放在不同的头文件中,在主文件(包含主函数的文件)需要用这些类时,就用#include指令将这些头文件包含进来。
由于各头文件是由不同的人设计的,有可能在不同的头文件中用了相同的名字来命名所定义的类或函数。这样在程序中就会出现名字冲突。
🌻例子
程序员甲在头文件header1.h中定义了类Student和函数fun:
#pragma once
//header1.h
#include <iostream>
#include<string>
#include <cmath>
using namespace std;
class Student //声明Student类
{
public:
Student(int n, string nam, int a)
{
num = n;
name = nam;
age = a;
}
void get_data();
private:
int num;
string name;
int age;
};
//成员函数的定义
void Student::get_data()
{
cout<< num <<"" << name << "" << age << endl;
}
//定义全局函数(即外部函数)
double fun(double a, double b)
{
return sqrt(a + b);
}
在main函数所在的主文件中包含文件header1.h:
#include "header1.h"
int main()
{
Student stud1(101,"Wang",18);
stud1.get_data;
cout<<fun(5,3)<<endl;
return 0;
}
运行结果如下:
如果程序员乙写了头文件head2.h,在其中定义了其他类以外,还定义了类Student和函数fun,但其内容与头文件header1.h中的Student和函数fun有所不同。
//header2.h
#pragma once
#include <string.h>
#include<cmath>
#include<iostream>
using namespace std;
class Student
{
public:
Student(int n, string nam, char s)//参数与header1.h中不同
{
num = n;
name = nam;
sex = s;
}
void get_data();
private:
int num;
string name;
char sex;
};
//成员函数定义
void Student::get_data()
{
cout << num << "" << name << "" << sex << endl;
}
//定义全局函数
double fun(double a, double b)
{
return sqrt(a - b);//返回值与header1中的fun函数不同
}
......
//头文件2可能还有其他的内容
假如主程序员在其程序中要用到header1.h中的Student和函数fun,因而在程序中包含了头文件header1.h,同时又要用到头文件header2.h中的一些内容,但是不知道此时header2.h中包含了与header1.h同名单内容不同的Student类和fun函数,因而又在头文件中包含了头文件header2.h。
主文件如下:
//main file
#include <iostream>
#include "header1.h"
#include "header2.h"
int main()
{
Student stud1(101,"Wang",18);
stud1.get_data;
cout<<fun(5,3)<<endl;
return 0;
}
这时,程序编译就会出现错误。
🌻名字冲突
因为在预编译后,头文件中的内容取代了对应的#include指令,这样就在同一个程序文件中出现了两个Student类和两个fun函数,显然是重复定义,这就是名字冲突。
名字冲突,即在同一个作用域中含有两个或多个同名的实体。
不仅如此,在程序中往往还需要引用一些库,包括C++编译系统提供的库、由软件开发商提供的库或者用户自己开发的库,为此需要包含有关的头文件。如果在这些库中包含有与程序的全局实体同名的实体,或者不同的库中有相同的实体名,则在编译时就会出现名字冲突。有人称之为全局命名空间污染。
🌼命名空间
为了解决这个问题,ANSI C++增加了命名空间。
所谓命命名空间,就是一个由程序设计者命名的内存区域。程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分离开来。
我的理解就是原来我们的全局实体变量都是“暴露出来”的,然后命名空间的作用就是分别个你需要的全局实体“围起来”,像栅栏一样,每一块区域都有一个专属于自己的名字。然后在编译阶段,就像是好多个“围起来的栅栏”,且各不相同。
命名空间的作用是建立一些互相分隔的作用域,把一些全局实体分隔开来,以免产生名字冲突。
可以根据需要设置许多个命名空间,每个命名空间代表一个不同的命名空间域,不同的命名空间不能同名。这样,可以把不同的库中的实体放到不同的命名空间中,或者说,用不同的命名空间把不同的实体隐藏起来。过去用的全局变量可以理解为存在于全局命名空间,独立域所有有名的命名空间之外,不是不需要namespace声明的,实际上是由系统隐式声明的,在该空间中有效。
🌻命名空间的类型
在声明一个命名空间时,花括号内不仅可以包括变量,而且还可以包括一下类型:
- 变量(可以带有初始化);
- 常量;
- 函数(可以是定义或声明);
- 结构体;
- 类;
- 模板;
- 命名空间(在一个命名空间中又定义了一个命名空间,即嵌套的命名空间)。
🌻命名空间的成员
例如:
namespace ns1 //指定命名空间ns1
{
int a;
double b;
}
- ns1是命名空间的名字。
- 在花括号内,声明的实体即为命名空间的成员,包括全局变量a和b。
- 使用a和b,需要加上命名空间和作用域分辨符"::",如ns1::a,ns1::b。
- 需要注意的是,a和b仍然是全局变量,仅仅是把他们放在了命名空间中而已。
🌻命名空间的使用
举例如下:
namespace ns1
{
const int RATE=0.08;//常量
double pay;//变量
double tax()//函数
{
return a*RATE;
}
namespace ns2 //嵌套命名空间
{
int age;
}
}
输出命名空间中ns1中成员的数据:
cout<<ns1::RATE<<endl;
cout<<ns1::pay<<endl;
cout<<ns1::tax()<<end;
cout<<ns1::ns2::age<<endl;
🌼使用命名空间解决名字冲突
声明命名空间ns1,并在命名空间ns1中声明Student类和定义成员函数、定义fun函数。
#pragma once
//header1.h
#include <iostream>
#include<string>
#include <cmath>
using namespace std;
namespace ns1 {
class Student //声明Student类
{
public:
Student(int n, string nam, int a)
{
num = n;
name = nam;
age = a;
}
void get_data();
private:
int num;
string name;
int age;
};
//成员函数的定义
void Student::get_data()
{
cout << num << "" << name << "" << age << endl;
}
//定义全局函数(即外部函数)
double fun(double a, double b)
{
return sqrt(a + b);
}
}
在header2.h中,声明命名空间ns2,并在命名空间ns2中定义Student类和 成员函数以及fun函数。
using namespace std;
namespace ns2
{
class Student
{
public:
Student(int n, string nam, char s)//参数与header1.h中不同
{
num = n;
name = nam;
sex = s;
}
void get_data();
private:
int num;
string name;
char sex;
};
//成员函数定义
void Student::get_data()
{
cout << num << "" << name << "" << sex << endl;
}
//定义全局函数
double fun(double a, double b)
{
return sqrt(a - b);//返回值与header1中的fun函数不同
}
}
主函数如下:
#include "header1.h";
#include "header2.h";
int main()
{
ns1::Student stud1(101, "Wang", 18);//用命名空间ns1中的Student类定义stud1
stud1.get_data();
cout <<ns1:: fun(5, 3) << endl;//调用命名空间ns1中的fun函数
ns2::Student stud2(102, "Li", 'f');//用命名空间ns2中的Student类定义stud2
stud2.get_data();
cout << ns2::fun(5, 3) << endl;//调用命名空间ns2中的fun函数
return 0;
}
运行结果如下: