C++ 命名空间避免命名冲突的实现

 更新时间:2024年03月07日 09:03:00   作者:釉色清风  
命名空间是C++中用来避免命名冲突的一种机制,本文主要介绍了C++ 命名空间避免命名冲突的实现,具有一定的参考价值,感兴趣的可以了解一下

🌼名字冲突问题

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

假如不同的人分别定义了类,放在不同的头文件中,在主文件(包含主函数的文件)需要用这些类时,就用#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++编译系统提供的库、由软件开发商提供的库或者用户自己开发的库,为此需要包含有关的头文件。如果在这些库中包含有与程序的全局实体同名的实体,或者不同的库中有相同的实体名,则在编译时就会出现名字冲突。有人称之为全局命名空间污染。

为了避免这类问题的出现,人们提出了许多方法,例如:将实体的名字写得长一点(包含十几个或几十个字母和字符);把名字搞得特殊一些,包括一些特殊的字符;由编译系统提供的内部全局标识符都用下划线作为前缀,如_complex(),以避免与用户的实体同名;由软件开发商提供的尸体的名字用特定的字符作为前缀等。但是这样的效果并不理想,而且增加了阅读程序的难度,即可读性降低了。

C语言和早期的C++语言没有提供有效的机制来解决这个问题,没有库的提供者能够建立自己的命名空间。人们希望ANSI C++ 标准库能够解决这个问题,提供一种机制、一种工具,使由库的设计者命名的全局标识符能够和程序的全局实体名以及其他类的全局标识符区别开来。

🌼命名空间

为了解决这个问题,ANSI C++增加了命名空间。

所谓命命名空间,就是一个由程序设计者命名的内存区域。程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分离开来。

我的理解就是原来我们的全局实体变量都是“暴露出来”的,然后命名空间的作用就是分别个你需要的全局实体“围起来”,像栅栏一样,每一块区域都有一个专属于自己的名字。然后在编译阶段,就像是好多个“围起来的栅栏”,且各不相同。

命名空间的作用是建立一些互相分隔的作用域,把一些全局实体分隔开来,以免产生名字冲突。

这里有一段很形象的描述,可以帮助大家更好地理解:例如,某中学高三年级有3个叫李相国的学生,如果都在同一班,那么老师点名叫李相国时,3个人都站起来应答,这就是名字冲突。因为他们无法辨别老师想叫的是哪一个李相国?同名者无法互相区分。为了避免同名混淆,学校把3个同名的学生分在3个班。这样,在小班点名叫李相国时,只会有一个人应答。也就是说,在该班的范围内,即班作用域内名字是唯一的。如果在全校集合时校长点名,需要在全校范围内找这个学生,要考虑的作用域是全校范围。如果校长叫李相国,全校学生中又会有3个人一齐喊“到”,因为在同一作用域中存在3个同名学生。为了在全校范围内区分这3名学生,即加上班名限定。这样就不会产生混淆。

可以根据需要设置许多个命名空间,每个命名空间代表一个不同的命名空间域,不同的命名空间不能同名。这样,可以把不同的库中的实体放到不同的命名空间中,或者说,用不同的命名空间把不同的实体隐藏起来。过去用的全局变量可以理解为存在于全局命名空间,独立域所有有名的命名空间之外,不是不需要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++ 命名空间避免命名冲突的实现的文章就介绍到这了,更多相关C++ 命名空间避免命名冲突内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Qt实现俄罗斯方块

    Qt实现俄罗斯方块

    这篇文章主要为大家详细介绍了Qt实现俄罗斯方块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • C/C++ 开发神器CLion使用入门超详细教程

    C/C++ 开发神器CLion使用入门超详细教程

    这篇文章主要介绍了C/C++ 开发神器CLion使用入门超详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • Qt使用HTTP上传json格式数据

    Qt使用HTTP上传json格式数据

    这篇文章主要为大家详细介绍了Qt如何使用HTTP上传json格式数据,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下
    2024-12-12
  • OpenCV实现绘制轮廓外接矩形

    OpenCV实现绘制轮廓外接矩形

    这篇文章主要为大家详细介绍了OpenCV实现绘制轮廓外接矩形的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-12-12
  • 详解C++最小惊讶原则

    详解C++最小惊讶原则

    本文主要介绍了详解C++最小惊讶原则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-03-03
  • C++ 中RTTI的使用方法详解

    C++ 中RTTI的使用方法详解

    这篇文章主要介绍了C++ 中RTTI的使用方法详解的相关资料,希望通过本文大家能理解使用RTTI,需要的朋友可以参考下
    2017-09-09
  • Cocos2d-x学习笔记之世界坐标系、本地坐标系、opengl坐标系、屏幕坐标系

    Cocos2d-x学习笔记之世界坐标系、本地坐标系、opengl坐标系、屏幕坐标系

    这篇文章主要介绍了Cocos2d-x学习笔记之世界坐标系、本地坐标系、opengl坐标系、屏幕坐标系,本文用代码和注释讲解了Cocos2d-x中的坐标体系,需要的朋友可以参考下
    2014-09-09
  • C++项目开发实现图书管理系统

    C++项目开发实现图书管理系统

    这篇文章主要为大家详细介绍了C++项目开发实现图书管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C语言全面细致精讲关键字的使用

    C语言全面细致精讲关键字的使用

    关键字是C语言非常重要的一部分,熟练的掌握和使用关键字有助于我们更加熟悉了解C语言,同时C语言的关键字也是面试笔试中常考的内容。C语言的关键字共有32个,但并不是每个关键字都有坑,本篇文章将通过理论联系实际的方式为大家讲解C语言中易混易错以及常考的一些关键字
    2022-05-05
  • 浅谈C++变量作用域

    浅谈C++变量作用域

    这篇文章主要介绍了C++变量作用域的的相关资料,文中代码非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06

最新评论