当前位置: 首页 > news >正文

命名空间与匿名空间

为什么要使用命名空间?


一个大型的工程往往是由若干个人独立完成的,不同的人分别完成不同的部分,最后再组合成一个完整的程序。由于各个头文件是由不同的人设计的,有可能在不同的头文件中用了相同的名字来命名所定义的类或函数,这样在程序中就会出现名字冲突。不仅如此,有可能我们自己定义的名字会与C++库中的名字发生冲突。名字冲突就是在同一个作用域中有两个或多个同名的实体,为了解决命名冲突 ,C++中引入了命名空间,

所谓命名空间就是一个可以由用户自己定义的作用域,在不同的作用域中可以定义相同名字的变量,互不干扰,系统能够区分它们。

什么是命名空间?

命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限制,从而合理的解决命名冲突。

C++中定义命名空间的基本格式如下:

namespace wd
{
int val1 = 0;
char val2;
}// end of namespace wd

在声明一个命名空间时,大括号内不仅可以存放变量,还可以存放以下类型:
变量
常量
函数,可以是定义或声明
结构体

模板
命名空间,可以嵌套定义如下

namespace wd
{
int number = 0;
struct Foo
{
char ch;
int val;
};
void display();
}// end of namespace wd

定义在名称空间中的变量或者函数都称为实体,名称空间中的实体作用域是全局的, 并不意味着其可见域是全局的。如果不使用作用域限定符和using机制,抛开名称空间嵌套和内部屏蔽的情况,实体的可见域是从实体创建到该名称空间结束。
在名称空间外,该实体是不可见的。

命名空间的使用方式

命名空间一共有三种使用方式,分别是

1.using编译指令

2.作用域限定符

3.using声明机制

using编译指令:

我们接触的第一个C++程序基本上都是这样的,其中std代表的是标准命名空间。

#include<iostream>
// using namespace std; 是using编译指令,引入了整个std命名空间
// 可以使用std命名空间中的所有实体,但在大型项目中不推荐全局使用
using namespace std; // std表示C++标准库的命名空间void test()
{// 由于使用了using namespace std,可以直接使用cout和endl// cout是std::ostream类的一个预定义全局对象(标准输出流)// endl是一个操纵器函数,用于插入换行符并刷新输出缓冲区cout << "Hello World!" << endl;
}int main()
{test();return 0;
}

其中第二行就使用了using编译指令。如果一个名称空间中有多个实体,使用using编译指令,就会把该空间中的所有实体一次性引入到程序之中;对于初学者来说,如果对一个命名空间中的实体并不熟悉时,直接使用这种方式,有可能还是会造成名字冲突的问题,而且出现错误之后,还不好查找错误的原因,比如下面的程序就会报错,当然该错误是人为造成的。

#include <iostream>
using namespace std;
double cout()
{return 1.1;
}
int main(void)
{cout();return 0;
}

作用域限定符:

第二种方式就是直接使用作用域限定符::啦。每次要使用某个名称空间中的实体时,都直接加上,例如:

#include<iostream>namespace zjy
{int num = 19;void display(){//cout,endl都是std空间中的实体,所以都加上'std::'命名空间std::cout << "zjy::display()" << std::endl;}
}
void test()
{std::cout << zjy::num << std::endl;zjy::display();
}int main()
{test();return 0;
}

这种方式会显得比较冗余,所以还可以采用第三种使用方式。

using声明机制:

using声明机制的作用域是从using语句开始,到using所在的作用域结束。要注意,在同一作用域内用。
using声明的不同的命名空间的成员不能有同名的成员,否则会发生重定义。

#include <iostream>
using std::cout;
using std::endl;namespace zjy
{int number = 10;void display(){cout << "zjy::display()" << endl;}
}
using zjy::number;
using zjy::display;void test()
{cout << "zjy::number = " << number << endl;display();
}
int main()
{test();return 0;
}

在这三种方式之中,我们推荐使用的就是第三种,需要哪个实体的时候就引入到程序中,不需要的实体就不引入,尽可能减小犯错误的概率。

namespace的嵌套使用:

#include <iostream>
using std::cout;
using std::endl;namespace zjy
{int number = 1;void display(){cout << "zjy::display()" << endl;}namespace cpp
{int number = 11;void display(){cout << "zjy::cpp::display()" << endl;}}//end of cpp}//end of zjyvoid test()
{zjy::display();cout << zjy::number << endl;zjy::cpp::display();cout << zjy::cpp::number << endl;
}
int main()
{test();return 0;
}

感觉和文件目录很像,一层一层的

匿名命名空间:

命名空间还可以不定义名字,不定义名字的命名空间称为匿名命名空间。由于没有名字,该空间中的实体,其它文件无法引用,它只能在本文件的作用域内有效,它的作用域是从匿名命名空间声明开始到本文件结束。在本文件使用无名命名空间成员时不必用命名空间限定。其实匿名命名空间和static是同样的道理,都是只在本文件内有效,无法被其它文件引用。

namespace 
{
int val1 = 10;
void func();
}//end of anonymous namespace

在匿名空间中创建的全局变量,具有全局生存期,却只能被本空间内的函数等访问,是static变量的有效替代手段。

#include <iostream>
using std::cout;
using std::endl;//匿名命名空间,没有名字
//只能在当前命名空间使用namespace
{int number = 1;
}
void test()
{cout << number << endl;
}
int main()
{test();return 0;
}

匿名空间存在的意义:

匿名命名空间在C++中存在的核心意义在于提供了一种强有力且一致的封装机制,它:

  • 保护实现细节不被意外使用

  • 防止跨文件的命名冲突

  • 提供比static更全面和现代的作用域控制

  • 促进更好的软件架构设计

  • 为编译器优化创造更多机会

  • 支持现代C++编程的最佳实践

这种设计体现了C++"你不用的东西不需要付出代价"的零开销原则,同时为大型软件项目的可维护性和健壮性提供了重要保障。

全局命名空间:

全局命名空间是C++程序中最基础、最外层的命名空间,它是所有命名空间的根源和起点。在C++程序中,任何没有显式指定命名空间的标识符都默认属于全局命名空间。这个命名空间没有具体的名称,但可以通过空的作用域解析运算符"::"来显式访问。

#include <iostream>
using std::cout;
using std::endl;void test()
{//printf()是c语言中的函数,在c++中有它的命名空间吗//其实c语言中的函数都在全局命名空间中//可以通过::来访问它::printf("Hello World\n");
}
int main()
{test();return 0;
}

核心特征

隐式存在性
全局命名空间不需要程序员显式声明,它是编译器自动创建和维护的。当我们在代码中直接定义函数、变量或类而不将其放入任何命名空间时,这些实体就自动归属于全局命名空间。

访问机制
访问全局命名空间中的成员有两种方式:隐式访问和显式访问。隐式访问是直接使用标识符名称,编译器会自动在全局命名空间中查找;显式访问则是使用"::"前缀,如"::functionName",这种方式可以明确指示编译器在全局命名空间中查找,避免与局部或其他命名空间中的同名标识符冲突。

链接性规则
全局命名空间中的实体默认具有外部链接特性,这意味着它们可以被程序中的其他翻译单元(源文件)访问。然而,通过使用static关键字或const限定符(在C++中const全局变量默认具有内部链接),可以限制其链接性,使其仅在当前文件内可见。

内容组成

内置类型与函数
全局命名空间包含了C++语言的所有内置数据类型(如int、float、char等)和基本操作。同时,当使用C风格头文件(如<stdio.h>、<stdlib.h>)时,相应的C标准库函数也会被放置在全局命名空间中。

用户定义实体
程序员定义的全局函数、全局变量、全局类和全局枚举等,只要没有显式放入特定命名空间,都会成为全局命名空间的成员。

特殊函数
程序的入口点main函数必须位于全局命名空间中,这是C++语言标准的规定。此外,全局操作符函数和全局友元函数也属于全局命名空间。

匿名命名空间 vs 全局命名空间对比

定义与标识

  • 匿名命名空间:没有名称的命名空间,使用 namespace {} 语法定义

  • 全局命名空间:默认的根命名空间,所有不在显式命名空间中的实体都位于此

作用范围

  • 匿名命名空间:仅限于定义它的当前文件内部,从声明处到文件结束

  • 全局命名空间:整个程序范围内可见,可被所有文件访问

链接性

  • 匿名命名空间:内部链接,实体对其他翻译单元完全不可见

  • 全局命名空间:默认外部链接,实体可被其他文件引用(除非使用static限制)

访问方式

  • 匿名命名空间:直接使用成员名称,无法使用命名空间限定符(因为没有名称)

  • 全局命名空间:可直接使用名称,也可用 :: 前缀显式指定

主要用途

  • 匿名命名空间:隐藏文件内部的实现细节,防止命名冲突,替代static关键字

  • 全局命名空间:放置真正需要全局访问的实体,与C语言库交互

设计意图

  • 匿名命名空间:封装和隔离,促进模块化设计,避免意外依赖

  • 全局命名空间:提供程序级共享机制,维护与C语言的兼容性

现代实践

  • 匿名命名空间:推荐用于文件局部实体,替代传统的static用法

  • 全局命名空间:应谨慎使用,避免污染,优先考虑自定义命名空间

匿名命名空间强调封装和隔离,全局命名空间强调共享和兼容,两者在C++中各有其不可替代的作用。

http://www.dtcms.com/a/602508.html

相关文章:

  • iOS arm64e hook MGCopyAnswer got Crash or Only Partial results got hooked
  • 天津建设银行官网站首页教学督导网站建设报告
  • 网站建设行业数据手机网站静态动态
  • 初学C语言编译器选择 | 适合新手的C语言编译器推荐
  • SOME/IP协议简要介绍
  • Kettle——this connection is closed
  • 传统网站 手机网站怎么做网站的签约编辑
  • C语言编译器手机版 | 高效学习与移动编程利器
  • 做cpc不做网站可以吗怎么才能创建个人网站
  • 安徽智能网站建设推荐网站开发应该注意什么
  • 易语言反编译成源代码 | 解密易语言反编译的技术与应用
  • 易语言加密模块反编译 | 深入解析加密模块反编译技术及应用
  • c语言编译器软件下载
  • 【C++11】C++11新特性(下)
  • 免费建站并且绑定域名专业的集团网站建设
  • 接计设做的网站广西网红
  • 技术指标时空编码构建LSTM兼容的量化交易特征工程体系
  • 网站开发培训深圳高端品质网站建设
  • 自然语言编程,举个反面案例
  • Spring 框架核心技术详解:AOP、JDBC 模板与事务管理
  • 杭州做外贸网站网站编辑工具软件
  • 《C++ Primer》和《Effective C++》哪个更厚?
  • 做海报那个网站好一分钟赚50元的游戏
  • 封装了 Android 权限检查和申请功能 PermissionManager工具类,支持权限检查、申请、说明对话框显示和设置页面引导等功能。
  • 2.GPU 网络架构全栈规划与深度分析:从业务需求到落地优化(H100/H200/B200/GB200 实战视角)
  • 企业网站手机端跳转设置门户cms系统
  • 鞍山58路公交车路线苏州百度seo关键词优化
  • 大储和工商储的差异
  • Windows 终端延迟剖析:从“卡顿感”到毫秒账本
  • wordpress图片自动分页插件下载关键词排名优化工具