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

C++名称空间

名称空间

名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。因此,在默认情况下,在名称空间中声明的名称的链接性为外部的(除非它引用了常量)

名称空间是开放的,你可以在名称空间中追加内容

namespace geo{double x;double y;void func(); //函数原型
} 
namespace geo{double z;  // z 也会放入名称空间void func(){std::cout << "func \n" ;}				// 你可以在这里实现函数原型
}

注意不能在名称空间完成赋值操作,如果想初始化则必须写成初始化的形式

namespace geo{double x =100; //可以初始化x = 1.5; // 不能赋值,这条语句将会报错
}

你也可以将函数的声明和定义写在一起,就不用提供原型

namespace geo{
double add(double x,double y){return x+y;
}
}

也可以分文件进行编写,将原型写到头文件里

// head.h
#pragma once
namespace geo{double add(double,double);                                                           
}
// main.cpp
#include <iostream>
#include "head.h"
double geo::add(double x,double y){return x+y;
}
int main()
{std::cout << geo::add(1.0,3.0) << '\n';                                              return 0;
}

你可以看到和类的定义写法差不多,可以分文件进行编写

在局部变量隐藏了全局变量的时候,如何调用全局变量?

#include <iostream>
int x = 100;
int main()
{using namespace std;int x =10;cout << "local var x = " <<  x << " &x = " << &x <<endl;cout << "global var x = " <<  ::x << " &x = " << &::x <<endl;                        return 0;
}

在这里插入图片描述

默认全局变量都会处于全局名称空间,你可以通过::操作符来获取全局变量,如果你自己定义了一个全局名称空间例如geo你也可以通过 ::geo::x来访问geo里面的变量,但是这没什么意义,你本可以直接用geo::x,不过从这里你可以看出geo是属于全局名称空间的一部分,可能你会想起前面提到的,名称空间定义是全局的或者位于另一个名称空间里。

你可以利用namespace给名称空间取别名

namespace geox = geo;  

这句话会让geox成为geo的别名,这种用法在存在名称空间嵌套的时候比较要用例如

  namespace geo{namespace line{int x;}}namespace geox = geo::line; //这会让geox变为geo::line的别名

using关键字

  1. using声明,你可以使用using namespace::var来进行使用var,例如经常使用的using std::coutstd为标准名称空间
  2. using编译指令,这会将名称空间的所有名称都可用,例如using namespace std,这样你就能尽情使用标准名称空间的内容

这两者有什么区别?
using声明就是真实的声明,你使用了之后就不能声明相同的名字的变量,例如如下的代码不能通过编译

  #include <iostream>namespace geo{int x;}int main(){using geo::x;double x;  // 出现声明冲突                                                                         return 0;}

using编译指令是允许你定义重名的变量,这会隐藏掉名称空间里面的变量

#include <iostream>
namespace geo{int x;
}
int main()
{using namespace geo;double x=100;std::cout << "x = "<< x << " &x = " << &x <<std::endl;std::cout << "geo::x = "<< geo::x << " &x = " << &geo::x <<std::endl;  // 覆盖后还想调用则使用geo::             return 0;
}

在这里插入图片描述
如果有两个名称空间有同名变量会发生什么?

  #include <iostream>namespace geo{int x=0;}namespace geox{int x =1;}int main(){using namespace geo;std::cout << "x = "<< x << " &x = " << &x <<std::endl;using namespace geox;std::cout << "x = "<< x << " &x = " << &x <<std::endl;return 0;                                                                          }

答案是这无法通过编译,会产生模糊定义,编译器不知道选择哪个x(即使你后用的using编译指令也无法覆盖前面的定义)
如果混用using声明会发生什么?

#include <iostream>
namespace geo{int x=0;
}
namespace geox{int x =1;
}
int main()
{using geo::x;std::cout << "x = "<< x << " &x = " << &x <<std::endl;                               using namespace geox;std::cout << "x = "<< x << " &x = " << &x <<std::endl;return 0;
}

答案是两个x均是0,因为using声明的行为就是声明,他会覆盖掉using编译的结果,即使编译命令在后面
在这里插入图片描述
如果都使用using声明可以吗?

  #include <iostream>namespace geo{int x=0;}namespace geox{int x =1;}int main(){using geo::x;std::cout << "x = "<< x << " &x = " << &x <<std::endl;using geox::x;std::cout << "x = "<< x << " &x = " << &x <<std::endl;                             return 0;    }   

想必你已经想到了结果,因为using声明就是声明!这会产生重定义,而不能通过编译

其他特性

可以在名称空间中使用using关键字

namespace geo{int y = 1;int x =100;namespace line{int x=0;}                                                                                    
}
namespace geox{using namespace geo;using geo::line::x;int y =100;
}

我这里面其实有很多问题,先要说明的是using编译指令具有传递性
使用

using namespace geox;

相当于

using namespace geox;
using namespace geo;

注意没有 using geo::line::x因为这是声明而不是编译指令
所以

using namespace geox;
std::cout << x ; //模糊的定义

因为geox中有一个xgeo中也有一个x这和之前提到的两个名称空间具有相同的名称是一样的

接下来分析一下geox::x的值是多少?
前面说过声明会覆盖using编译指令,所以geox中的x实际上是geo::line::x的别名,所以值为0

同样

using namespace geox;
std::cout << y ; //模糊的定义

这里就很好理解了,geox包含了自己定义的ygeo也一样和前面的情况完全一致。

接下来注意名称空间中使用using namespace geo并不意味着geox包含了geo,而是相当于把,geo里面的名称都导入了geox,这可以被覆盖,我们前面诸多例子说明了这个现象,所以你其实不能用geox::geo,但是你可以用geox::line这与geo::line完全相同,可以理解为别名

最后看一种更为复杂的情况

  #include <iostream>namespace geo{namespace line{int x=0;}}namespace geox{using namespace geo;namespace line{int y=10;}}int main(){using namespace geox;using namespace std;cout << line::x; // 模糊的定义                                                                   return 0;}     

这会编译出错,因为无法确定使用哪一个line,因为即使你使用using name geogeox包含了geo的内容,可能你以为这可以利用namespace的开放原则,可以将int y=10;添加到geo中,但实际上不行,编译器只会看到geox自己定义的line,由于前面提到的using 传递原则所以会出现模糊的定义,因为有两个line都可见,这与前面提到的两个名称空间包含相同的名称类似,并且你没有办法通过geox访问到geo中的内容,这一点很有意思

匿名namespace
实现文件作用域的静态变量替代方案,使得变量具有内部链接,别的文件不可见

namespace {int x; // x是静态变量 ,具有内部链接性
}

这个效果于static int x;
但是匿名namespace的好处更多

  1. 可以分组对一批内容设定内部链接性
  2. 支持模板,类/结构 ,static无法修饰这些

相关文章:

  • 介词:连接名词与句子其他成分的桥梁
  • VSCode通过SSH连接VMware虚拟机
  • JAVA---多态
  • 48变现干货:分销裂变方式提高销量
  • Go语言chan底层原理
  • 前端小练习————表白墙+猜数字小游戏
  • Python Cookbook-6.19 调用超类的__init__方法
  • QT对象树
  • pip安装包时网络不畅,替换国内PyPI镜像源
  • Seata TCC 实战笔记:从零搭建分布式事务 Demo (含源码)
  • Android 常用输入控件
  • 6.城市综合管廊工程
  • FastApi快速实践
  • 一键获取当前项目的所有文件结构并保存到文本文件
  • ​​工业机器人智能编程:从示教器到AI自主决策​​
  • 雅思听力--75个重点单词/词组
  • 在JSP写入Text文件方法指南
  • go语言实现用户管理系统
  • 【2025软考高级架构师】——2024年11月份真题与解析
  • 使用 OpenCV 和 Dlib实现轮廓绘制
  • 习近平给谢依特小学戍边支教西部计划志愿者服务队队员回信
  • “矿茅”国际化才刚开始?紫金矿业拟分拆境外黄金矿山资产于港交所上市
  • 王毅在金砖正式成员和伙伴国外长会上的发言
  • 挑大梁!一季度北上广等7省份进出口占外贸总值四分之三
  • 魔都眼|西岸国际咖啡生活节:连接艺术、音乐与宠物
  • 见证历史与未来共舞:上海西岸“蝶变共生”对话讲坛圆满举行