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++ 命名空间避免命名冲突内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 深入N皇后问题的两个最高效算法的详解

    深入N皇后问题的两个最高效算法的详解

    本篇文章是对N皇后问题的两个最高效的算法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C/C++中使用列表框组件Qt ListWidget

    C/C++中使用列表框组件Qt ListWidget

    本文详细讲解了C/C++中使用列表框组件Qt ListWidget的方法,文中通过示例代码介绍的非常详细。对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-11-11
  • C++ Boost StringAlgorithms超详细讲解

    C++ Boost StringAlgorithms超详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • C++实现主机字节序和网络字节序转换示例

    C++实现主机字节序和网络字节序转换示例

    这篇文章主要为大家介绍了C++实现主机字节序和网络字节序转换示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • C++面试题之进制转换的实例

    C++面试题之进制转换的实例

    这篇文章主要介绍了C++面试题之进制转换的实例的相关资料,希望通过本文能帮助到大家,让大家理解掌握这样的知识,需要的朋友可以参考下
    2017-10-10
  • 深入解析C++中的虚函数与多态

    深入解析C++中的虚函数与多态

    对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)和一个指向虚函数表的指针(vptr)来实现的
    2013-09-09
  • Qt6实现调用摄像头并显示画面

    Qt6实现调用摄像头并显示画面

    这篇文章主要为大家详细介绍了Qt6如何实现调用摄像头并显示画面的效果,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2023-02-02
  • 面向对象三大特性的意义讲解

    面向对象三大特性的意义讲解

    今天小编就为大家分享一篇关于面向对象三大特性的意义讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C语言中的隐式函数声明

    C语言中的隐式函数声明

    在c语言里面开来还是要学习c++的编程习惯,使用函数之前一定要声明。不然,即使编译能通过,运行时也可能会出一些莫名其妙的问题。
    2016-01-01
  • C++中实现多态有几种方式小结

    C++中实现多态有几种方式小结

    在C++中,多态是一种面向对象编程的特性,允许以统一的方式处理不同类型的对象,并根据实际对象的类型来执行相应的操作,本文给大家介绍了C++中实现多态有几种方式小结,需要的朋友可以参考下
    2024-12-12

最新评论