🌼名字冲突问题

在实际生活中,一个大型的项目往往不是一个人独立完成的,而是由若干个人合作完成的,不同的人分别完成不同的部分,最后组合成一个完整的程序。

假如不同的人分别定义了类,放在不同的头文件中,在主文件(包含主函数的文件)需要用这些类时,就用#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;
}

运行结果如下:
【C++】用命名空间避免命名冲突-LMLPHP

如果程序员乙写了头文件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;
}

这时,程序编译就会出现错误。
【C++】用命名空间避免命名冲突-LMLPHP

🌻名字冲突

因为在预编译后,头文件中的内容取代了对应的#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;
}

运行结果如下:
【C++】用命名空间避免命名冲突-LMLPHP

03-06 12:30