【C++】1. 命名空间


一、命名空间的由来

当我们使用c语言编写项目时,可能遇到以下情况:

  1. 变量名与某个库函数名重复,导致保错。这种情况一般是自己不知道引用的头文件包含哪些库函数。

在这里插入图片描述
2. 和队友一起编写项目时,自己使用的标识符和队友的标识符名字一样,导致代码整合时发生错误。这种情况很难避免,毕竟一些常用的命名习惯是大家都有的,那这个时候怎么办呢?总不能打一架来争夺命名权。
在这里插入图片描述
基于这样的问题,c++的创造者创造了命名空间。

当多个库或代码文件被组合在一起时,可能会出现相同名称的变量、函数、类等,这种情况称为“命名冲突”。命名空间可以在不改变原有代码的情况下,将标识符放在特定的作用域中,以避免命名冲突。


二、命名空间的使用

上面提到,命名空间通过将标识符放在特定的作用域来解决命名冲突。这里出现一个名词:作用域。学过c语言的人应该都知道这个概念。

作用域是指在程序代码中,标识符有效的区域或范围。在作用域内,标识符可以被使用或修改,而在其它作用域内则可能无法访问该标识符。

变量只有在它的作用域里才能发挥它的作用。局部变量只能在局部域发挥作用,全局变量只有在全局域才能发挥作用。
由于作用域的存在,请问以下代码会发生命名冲突吗?
在这里插入图片描述
不会!因为两个a不在同一个域中。
编译器在使用a这个标识符时,一般按照以下顺序去寻找a:局部域->全局域。


因此我们按照这样的思路,来创建一个命名空间域存放我们设置的标识符。

2.1 关键字:namespace

namespace的使用如下:
在这里插入图片描述
此时sfw里的a就不会与sfw域外面的a产生冲突。
命名空间内部可以包含结构体,函数……


2.2 访问命名空间里的标识符

上面提到编译器查找标识符的顺序是 :局部域->全局域。
现在我们创建了sfw这个命名空间,那编译器此时访问顺序会变成什么?不变,因为编译器不会主动去访问命名空间里的内容。
在这里插入图片描述
那我们怎么访问命名空间里的标识符呢?有三种方法。

  1. 展开命名空间:通过使用using这个关键字,如下图
    在这里插入图片描述
    注意:展开命名空间相当于把这个命名空间暴露在全局域当中。
    这就意味着:如果此时全局域有一个标识符和sfw命名空间里一个标识符相同,则会发生命名冲突。如下图,因此不推荐这种玩法。
    在这里插入图片描述
    补:using namespace sfw;需要在sfw这个命名空间创建后才能使用,如果这句代码在namespace sfw {……}上面,则会报错

  1. 使用作用域限定符::来访问命名空间里的标识符 : 命名空间名字+::+标识符,如下图
    在这里插入图片描述
    这种方式就不用担心展开命名空间造成的错误了,因此这种方式往往是大型团队项目的使用方式

  1. 展开命名空间的某一部分:using + namespace + 命名空间的名字 + :: + 标识符
    在这里插入图片描述
    这种方式仍有展开命名空间相同的错误,比如此时刚好有个全局变量是a,一样也会报错。个人还是推荐第二种方式。

2.3 命名空间的特点

我们已经知道了如何创建和访问命名空间,下面我们来学习命名空间的一些特点。

  1. 命名空间的嵌套:一个命名空间可以包含另一个一个命名空间
    在这里插入图片描述

  2. 命名空间的合并
    请问:命名空间会发生命名冲突吗?即我创建了一个命名空间:sfw,你也创建了一个命名空间:sfw。
    答:冲了但也没冲。编译器会将相同名字的命名空间合在一起,如果这两个命名空间都定义了相同的标识符,则发生冲突。
    在这里插入图片描述


全局命名空间

在 C++ 中,:: 表示全局命名空间。::testing::Test 的写法确保访问的是全局命名空间下的 testing,而不会受到当前作用域内的命名空间或类的影响。这种写法通常用于避免命名冲突或保证代码在不同命名空间下依然可以正确访问 testing::Test

为什么加上 ::

在 Google Test 的代码中,加上 :: 可以防止可能的命名冲突。例如:

namespace mynamespace {
    void testing() {}  // 一个与 testing 同名的函数

    class MyTest : public ::testing::Test { // 使用全局的 testing::Test
        // 测试代码
    };
}

在这个例子中,如果没有 ::,编译器可能会认为 testing::Testmynamespace::testing::Test,而不是全局的 testing::Test,导致编译错误。加上 :: 后,即使在命名空间内也可以确保访问的是全局的 testing::Test

三、总结

命名空间是C++中用来避免命名冲突的一种机制。创建和使用命名空间的方法如下:

创建命名空间:在全局或其他命名空间的作用域内,使用关键字namespace加上命名空间的名称来创建一个命名空间,例如:

namespace my_namespace {
   // 命名空间的定义内容
}

命名空间中可以定义变量、函数、类等标识符,并给他们都加上该命名空间的前缀。例如:

namespace my_namespace {
    int my_var = 0;  // 定义命名空间内的变量
    void my_function() {  // 定义命名空间内的函数
        // 函数代码
    }
    class MyClass {  // 定义命名空间内的类
        // 类定义
    };
}

使用命名空间:在使用命名空间内的标识符时,需要在其前面加上命名空间的名称和作用域限定符(::),例如:

my_namespace::my_var = 100;   // 使用 my_namespace 命名空间内的变量
my_namespace::my_function();  // 调用 my_namespace 命名空间内的函数
my_namespace::MyClass obj;    // 使用 my_namespace 命名空间内的类

可以使用using关键字引入命名空间中的标识符,使得在该作用域内可以直接使用该标识符而不需要加上命名空间前缀。例如:

using my_namespace::my_var;
my_var = 100;   // 直接使用 my_var,无需加上命名空间前缀

命名空间的使用可以避免不同模块或工程中使用同名标识符导致的冲突问题,同时也便于代码维护和阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值