首页 > 编程语言 >C++名字空间

C++名字空间

时间:2024-10-09 18:59:37浏览次数:10  
标签:符号 作用域 C++ int 名字 空间 ns

基本概念

名字空间本质上是自定义作用域,由于C++设计的初衷是开发大规模软件,大量的软件库必然会加剧全局符号(变量、函数)的冲突,因此名字空间最基本的作用就是给不同的库和模块拥有自己的独特的作用域,处于不同名字空间中的重名符号相安无事,互不冲突,以此来大大提高编程的便利性。


1.1 定义与使用

定义一个名字空间,实际上就是定义一个作用域,在名字空间中可以定义变量、函数等,示例代码如下:

// ns.cpp
// 定义一个名字空间,叫ns
namespace ns
{
    // 在 ns 中定义变量
    int a = 1;

    // 在 ns 中定义函数
    float f(int x)
    {
        return x/2;
    }
}

在以上名字空间 ns 中,定义了一个变量 a 和一个函数 f,但实际上它们的名字是 ns::a 和 ns::f,比如如下示例代码显示了如何正确地引用它们:

// ns.h
namespace ns
{
    // 对名字空间 ns 中的符号进行声明
    extern int a;
    extern float f(int x);
}
// main.cpp
#include "ns.h"

int main()
{
    // 调用名字空间中的符号,使用全称
    cout << ns::a << endl;
    cout << ns::f(8) << endl;
}

此处出现了一个新的操作符 ==> :: ,其用法是:

名字空间::某符号
类::某符号

这个双冒号的操作符,称为作用域引用符,很显然,双冒号前面必须是一个作用域,在C++中,除了名字空间是作用域之外,后续会讲到的类也是最常见的作用域。

很显然,将全局变量 a 和函数 f() 放在名字空间中之后,可以极大避免由于不同程序文件或库的重名而引起的冲突。例如,在另外一个名字空间中,出现跟 ns 一样的变量或函数,它们一起使用相安无事:

// another_ns.cpp
namespace another_ns
{
    int a = 100;
}

// ns.h
namespace ns
{
    extern int a;
    extern float f(int x);
}
namespace another_ns
{
    extern int a;
}

// main.cpp
#include <iostream>
#include "ns.h"

int main(void)
{
    cout << ns::a << endl;         // 输出1
    cout << another_ns::a << endl; // 输出100
}

另外值得注意的是,名字空间是对变量和函数的定义的作用域规定范围,因此是出现在源文件 *.cpp 中的,而对这些符号的声明,跟原来做法的一样 —— 在对应的头文件中进行声明,只不过在带有名字空间的场合中,头文件的声明语句也同样要包含在名字空间中。


1.2 using语句

在上述代码 main.cpp 中,使用了全称 ns::a 和 ns:f 来引用符号,在实际应用中很显然是很不方便的,有没有办法不需要重复写名字空间的名字 ns 也能使用里面定义的符号呢?答案是肯定的,只需要使用 using 语句即可,比如上述源码 main.cpp 可改成如下形式:

// main.cpp
#include "ns.h"
using namespace ns; // 导入名字空间:ns
int main()
{
    // 调用名字空间 ns 中的符号,不再需要写全名了
    cout << a << endl;
    cout << f(8) << endl;
}

对上述代码,需要强调的一点是,using 语句其实有两种形式:

// 形式一:导入整个名字空间中的所有符号
using namespace ns;

// 形式二:导入名字空间中的指定符号
using ns::a;
using ns::f;

由于在上述例子中,名字空间 ns 仅仅包含极少量符号,因此不管采用哪种形式的 using 语句都没有什么区别,但如果某个名字空间包含大量符号(比如标准名字空间std),而程序中仅需用到其中的少量符号,那么导入整个名字空间的所有符号的做法也许是不明智的,因为这会使得大量未被使用的符号成为潜在的符号冲突候选人,这种情形被称为名字空间污染,因此,实际编码中我们应在追求便利的同时,尽量避免引入不使用的符号。


2. 进阶语法

2.1 内嵌名字空间

C++允许嵌套定义名字空间,即一个名字空间内部再出现另一个名字空间,这其实是作用域的常规特性,早在C语言时代就可以有嵌套的作用域的概念,只不过C语言中的作用域都是匿名的,而C++给这些作用域赋予了特定的名字。

// ns.cpp
namespace ns
{
    int a = 1; // 注意,此处a的全称是 ns::a

    // 在名字空间中嵌套另一个名字空间
    namespace nested_ns
    {
        int a = 2; // 注意,此处a的全称是 ns::nested_ns::a
        int x = 100;
    }
}

声明与使用:

// ns.h
namespace ns
{
    extern int a;
    namespace nested_ns
    {
        extern int a;
        extern int x;
    }
}

// main.cpp
#include "ns.h"

int main()
{
    cout << ns::a << endl;

    cout << ns::nested_ns::a << endl;
    cout << ns::nested_ns::x << endl;
}

2.2 扩展性
// main.cpp
#include <iostream>
#include "ns.h"

namespace ns
{
    // 在名字空间 ns 中增添一个新的符号b
    int b = 666; 
}

using namespace ns;

int main(void)
{
    cout << a << endl; // 访问名字空间 ns 中原有的符号 a
    cout << b << endl; // 访问名字空间 ns 中新增的符号 b
}

当程序在多处定义了相同的名字空间时,它们将会融合成一个统一的作用域。如:

// main.cpp
#include <iostream>
#include "ns.h"

namespace ns
{
    // 在名字空间 ns 中增添一个新的符号b
    int b = 666; 
}

using namespace ns;

int main(void)
{
    cout << a << endl; // 访问名字空间 ns 中原有的符号 a
    cout << b << endl; // 访问名字空间 ns 中新增的符号 b
}

2.3 全局作用域

全局作用域是从C语言就开始有的一种作用域,在C++中,有时为了强调某符号的全局特性,或为了避免与导入的名字空间中的重名符号冲突,会在使用全局符号的时候加上 作用域解析符

示例代码:

int global = 100;
int main()
{
    int global = 200;

    // 重名的标识符,外层的作用域会被内层的掩盖
    cout <<   global << endl; // 输出200

    // 使用双冒号引用全局作用域中的标识符
    cout << ::global << endl; // 输出100
}

全局作用域的名字空间是匿名的,引用全局作用域符号只需加 :: 即可。
名字空间的本质就是作用域,遵守C语言关于作用域的基本原则,如内层作用域重名符号会掩盖外层作用域的重名符号。


3. 小结

自定义名字空间,实际上是将原来C语言中的全局作用域做了更加细致的规划,在原先的全局作用域中,人为地将某个区域内的符号(变量、对象、函数)命个名圈起来,避免与全局作用域中的其余符号冲突。

如果不可避免地要引入不同的名字空间(比如space1和space2),并且不同的名字空间中恰巧有重名的符号(比如var),那么引用方只需将符号带上其所属的名字空间的名称即可(比如space1::var 和 space2::var)。这大大拓展了大型程序对不同函数库符号引入的灵活性,大大缓解了符号的冲突的可能。

引入名字空间的初衷,是解决大型软件中的各个不同产商提供的第三方库的名字冲突问题,这是从C语言到C++的一个重大的改变。

标签:符号,作用域,C++,int,名字,空间,ns
From: https://www.cnblogs.com/hhail08/p/18454932

相关文章

  • C++:自治我的世界2D.V0.0.4.5
    更新内容:增加挖掘进度,挖掘需要时间了,但还有BUG操作说明:A,D移动;W跳跃;上,下,右+上,右+下,左+上,左+下撸方块;M开关大地图#include<bits/stdc++.h>#include<windows.h>#defineKEY_DOWN(VK_NONAME)((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)usingnamespacestd;void......
  • C++消灭星星游戏编程【目录】
    欢迎来到zhooyu的专栏。主页:【zhooyu】专栏:【C++消灭星星游戏编程】特色:【保姆级教程,含每一课程源码】致力于用最简洁的语言,最简单的方式,最易懂的知识,带大家享受编程的快乐。消灭星星游戏编程演示效果消灭星星游戏编程演示效果本专栏内容:消灭星星的小游戏保姆......
  • 实验一 C++
    实验任务1:task1.cpp:1#include<iostream>2#include<string>3#include<vector>4#include<algorithm>56usingnamespacestd;78//声明9//模板函数声明10template<typenameT>11voidoutput(constT&c);1213......
  • 实验1 现代C++编程初体验
    任务一#include<iostream>#include<string>#include<vector>#include<algorithm>usingnamespacestd;template<typenameT>voidoutput(constT&c);voidtest1();voidtest2();voidtest3();intmain(){cout<<&qu......
  • C++编译并运行后出现Process finished with exit code 139 (interrupted by signal 11
    问题描述:        代码运行意外终止,报错信息为Processfinishedwithexitcode139(interruptedbysignal11:SIGSEGV)CMakeList文件如下:cmake_minimum_required(VERSION3.26)project(SLAM)set(CMAKE_CXX_STANDARD17)set(CMAKE_CXX_STANDARD_REQUIRED......
  • 调用sdapi/v1/txt2img接口,报错“Couldn‘t load custom C++ ops”
    后端启动stable_diffusion的api接口nohuppythonlaunch.py --use-cpuall--skip-torch-cuda-test   --api--api-log  --listen--server-name192.168.1.204>/home/third_party_app/llm/stable-diffusion-webui/logs/all.log2>&1 &服务接口http://192.168......
  • (2024最新毕设合集)基于SpringBoot的乡村书屋小程序-31881|可做计算机毕业设计JAVA、PHP
    摘要随着信息技术的快速发展和互联网的广泛普及,数字化服务的需求不断增长,乡村书屋作为传统的文化服务机构也需要适应这一变革。本研究将使用Java开发技术,通过springboot作为框架,结合微信小程序,和MySQL作为数据存储的技术,开发一套功能齐备可移动的乡村书屋小程序,旨在提升乡......
  • 【C++】priority_queue的介绍和模拟实现
    【C++】priority_queue的介绍和模拟实现一.priority_queue的介绍1.priority_queue的基本介绍2.priority_queue的使用介绍二.priority_queue的模拟实现一.priority_queue的介绍1.priority_queue的基本介绍优先队列是一种容器适配器,根据严格的弱排序标准,它的......
  • C++ day04(友元 friend、运算符重载、String字符串)
    目录【1】友元friend1》概念2》友元函数 3》友元类 4》友元成员函数 【2】运算符重载1》概念2》友元函数运算符重载 ​编辑 3》成员函数运算符重载4》赋值运算符与类型转换运算符重载 5》注意事项【3】String字符串类【1】友元friend1》概念定义:......
  • 《 C++ 修炼全景指南:十四 》大数据杀手锏:揭秘 C++ 中 BitSet 与 BloomFilter 的神奇性
    本篇博客深入探讨了C++中的两种重要数据结构——BitSet和BloomFilter。我们首先介绍了它们的基本概念和使用场景,然后详细分析了它们的实现方法,包括高效接口设计和性能优化策略。接着,我们通过对比这两种数据结构的性能,探讨了在不同应用场景中的选择依据。最后,博客还涵盖......