【C++】命名空间 ( namespace )

简介: 【C++】命名空间 ( namespace )

什么是命名空间

命名空间是一种用来避免命名冲突的机制,它可以将一段代码的名称隔离开,使其与其他代码的名称不冲突;

命名空间的原理是将一个全局的作用域分成一个个命名空间,每个命名空间是个单独的作用域,同时若是在同一个作用域内可能出现的命名冲突也不会造成影响,有效避免了命名空间的污染;


命名空间的作用

在学习C语言的过程中我们知道有一个函数叫做rand函数,该函数用于生成伪随机整数;

#include<stdio.h>
int rand = 10;
int main()
{
  printf("%d\n",rand);
  return 0;
}

上面的代码在.c文件下的情况执行会得出什么结果

代码被运行成功且没有什么错误

但若是在包含rand函数所在的头文件为前提的结果是什么?

当包含了rand函数所在的头文件即报错;

原因是,在程序运行时,计算机先会在局部寻找变量,当局部内未找到时则回去全局找;

在全局找时找到了两个 rand (一个为头文件内的rand函数,一个为所创建的变量rand)

此时也不知该打印哪一个rand,这就叫命名冲突;

但在C++中,出现了一个新的概念叫做命名空间,一般来说,rand这类的函数都存放于C++中标准库类型对象的命名空间std中

若是在编译器中执行这段代码结果是什么;

#include<iostream>//标准输入输出流头文件
using namespace std;//展开标准库命名空间std
namespace Sweet{//设置命名空间且名为Sweet
  int rand = 10;
}
int main()
{
  cout << rand << endl;//打印rand
  cout << Sweet::rand << endl;//打印Sweet中的rand(::符号为作用域限定符)
  return 0;
}

打印出来的结果没有报错,原因是在这里并没有发生命名冲突,在这段代码中使用了

namespace Sweet{
  int rand = 10;
}

设置了一个名为Sweet的命名空间,且在命名空间内声明变量rand,在打印过程中就相当于虽然重名但是所在班级不同的学生;

但此时的rand仍然处于全局空间中,只是隐藏在名为Sweet的命名空间内;

若是运行下面的代码,则结果是什么?

#include<iostream>
using namespace std;
namespace Sweet{
  int rand = 10;
}
using namespace Sweet;
int main()
{
  cout << rand << endl;
  cout << Sweet::rand<<endl;
  return 0;
}

为什么上面的代码运行时并没报错而这段代码报错了?


如何定义命名空间

从上面可知命名空间的作用,既然命名空间能够有效防止命名冲突,那该如何定义命名空间

在定义命名空间时,应该使用 namespace 修饰且在该修饰词后定义名字

并在其后跟**{ }**

在{ }内的元素即为该命名空间的成员

#include<iostream>
using namespace std;//展开std命名空间
namespace A1 {//定义一个名为A1的命名空间
  int a = 0;
  int b = 20;//变量
  void Add()//函数
  {
    cout << "IsAddFunc1" << endl;
  }
  struct TestNode//结构体
  {
    int test1;
    double test2;
  };
}
namespace A2 {//定义一个名为A2的命名空间
  int a = 10;
  int b = 21;
  void Add()
  {
    cout << "IsAddFunc2" << endl;
  }
  struct TestNode
  {
    int test3;
    double test4;
  };
}
int main()
{
  cout << "A1::b = " << A1::b << endl;//打印A1中的b
  cout << "A2::b = " << A2::b << endl;//打印A2中的b
  A1::Add();//调用A1中的Add函数
  A2::Add();//调用A2中的Add函数
  struct A1::TestNode AT1;//声明结构体变量
  struct A2::TestNode AT2;
  cout << &AT1 << endl;//打印结构体变量地址
  cout << &AT2 << endl;
  return 0;
}

从该段代码可知命名空间内不仅可以声明(定义)变量,还可以包含函数、类、typedef以及#define宏等等


命名空间的种类

在一般情况下,命名空间还可以进行嵌套,即可以在一个命名空间内嵌再嵌套命名空间,以此类推;

#include<iostream>
using namespace std;
namespace A1{
  int mi = 0;
  int qi = 5;
  namespace A2 {
    int qi = 10;
    namespace A3 {
      int mi = 25;
    }
  }
}
int main()
{
  cout << "A1::mi = " << A1::mi << endl;
  cout << "A1::qi = " << A1::qi << endl;
  cout << "A1::A2::qi = " << A1::A2::qi << endl;
  cout << "A1::A2::A3::mi = " << A1::A2::A3::mi << endl;
  return 0;
}

该处A1命名空间内嵌套着A2A2嵌套A3

注意: 命名空间只能在全局范围定义!!

故上图的使用方法为错误方法

如何使用命名空间内的成员

既然命名空间可以防止发生命名冲突,那放在命名空间的成员应该如何使用?

作用域限定符

在一般情况下,若是想使用命名空间内的成员,可以使用作用域限定符 ::(域解析操作符)

#include<iostream>
using namespace std;
namespace A1{
  int mi = 0;
  int qi = 5;
  namespace A2 {
    int qi = 10;
    namespace A3 {
      int mi = 25;
    }
  }
}
int main()
{
  cout << "A1::mi = " << A1::mi << endl;
  cout << "A1::qi = " << A1::qi << endl;
  cout << "A1::A2::qi = " << A1::A2::qi << endl;
  cout << "A1::A2::A3::mi = " << A1::A2::A3::mi << endl;
  return 0;
}

该段代码即使用了作用域限定符;

该符号的作用是通知编译器应从作用域限定符左侧的名字所示的作用域中寻找右侧那个名字,即指定访问哪个名字空间的哪个成员。


命名空间展开

除了可以使用作用域限定符进行操作以外还可以将命名空间展开,同时命名空间展开有两种

①命名空间全部展开

②命名空间部分展开

命名空间全部展开

命名空间全部展开需要使用

cpp using namespace xxx;

进行修饰;

#include<iostream>
using namespace std;
int main()
{
  cout<<"using namespace std"<<endl;
  return 0;
}

如上代码将标准库中的std命名空间展开,即可以在不受作作用域限定符的限制使用std命名空间内的cout与endl;

但若是将命名空间全部展开则也有一些麻烦;

例如:

该处将两个命名空间都进行了展开,导致程序在运行中从全局范围中找到了两个rand从而导致的“悲剧”;

故一般情况下,在项目中不支持以命名空间全部展开的方式使用命名空间内的成员;

命名空间部分展开

除了命名空间全部展开以外还有一种方式即相对的进行命名空间部分展开;

using XXX :: xxx;

以该方式将命名空间中的部分分支进行展开,即可以在不全部展开以及不使用作用域限定符的情况下使用命名空间内的成员;

#include<iostream>
using std::cout;//进行命名空间部分展开将std命名空间内的cout以及endl进行部分展开
using std::endl;//命名展开后可以在不影响该命名空间以内其他成员的情况下使用cout与endl
int main()
{
  cout << "Hello World" << endl;//打印"Hello World"
  return 0;
}

总结

①命名空间可以避免命名冲突问题;

②命名空间可以进行嵌套;

③命名空间必须在全局范围内定义,不可再局部范围内定义;

④在使用命名空间内的成员时共有三种方法(作用域限定符、命名空间全部展开、命名空间部分展开),在一般练习中尽量不要进行全部展开;

相关文章
|
1月前
|
安全 程序员 编译器
【C++】如何巧妙运用C++命名空间:初学者必备指南
【C++】如何巧妙运用C++命名空间:初学者必备指南
|
3月前
|
程序员 C++ 开发者
C++命名空间揭秘:一招解决全局冲突,让你的代码模块化战斗值飙升!
【8月更文挑战第22天】在C++中,命名空间是解决命名冲突的关键机制,它帮助开发者组织代码并提升可维护性。本文通过一个图形库开发案例,展示了如何利用命名空间避免圆形和矩形类间的命名冲突。通过定义和实现这些类,并在主函数中使用命名空间创建对象及调用方法,我们不仅解决了冲突问题,还提高了代码的模块化程度和组织结构。这为实际项目开发提供了宝贵的参考经验。
61 2
|
2月前
|
程序员 C++ 容器
C++编程基础:命名空间、输入输出与默认参数
命名空间、输入输出和函数默认参数是C++编程中的基础概念。合理地使用这些特性能够使代码更加清晰、模块化和易于管理。理解并掌握这些基础知识,对于每一个C++程序员来说都是非常重要的。通过上述介绍和示例,希望能够帮助你更好地理解和运用这些C++的基础特性。
40 0
|
3月前
|
编译器 C语言 C++
C++入门 | 命名空间、输入输出、缺省参数
C++入门 | 命名空间、输入输出、缺省参数
44 4
|
2月前
|
C语言 C++
C++(六)Namespace 命名空间
命名空间(Namespace)是为了解决大型项目中命名冲突而引入的机制。在多库集成时,不同类库可能包含同名函数或变量,导致冲突。C++通过语法形式定义了全局无名命名空间,并允许对全局函数和变量进行作用域划分。命名空间支持嵌套与合并,便于协同开发。其使用需谨慎处理同名冲突。
|
4月前
|
安全 编译器 C++
C++一分钟之-C++中的属性命名空间
【7月更文挑战第22天】C++11引入属性作为元数据,虽无内置属性命名空间,但可通过自定义属性与命名空间组合实现类似效果。例如,创建`perf`命名空间存放`slow`和`fast`属性来标记函数性能。正确使用属性需注意位置、避免重复和确保与实现一致,以提升代码可读性和编译器理解。通过模拟属性命名空间,可以更有效地管理和使用属性。
43 1
|
4月前
|
小程序 C++
【C++入门 二 】学习使用C++命名空间及其展开
【C++入门 二 】学习使用C++命名空间及其展开
|
4月前
|
C语言 C++ 开发者
C++基础知识(一:命名空间的各种使用方法)
C++在C的基础上引入了更多的元素,例如类,类的私密性要比C中的结构体更加优秀,引用,重载,命名空间,以及STL库,模板编程和更多的函数,在面向对象的编程上更加高效。C语言的优势则是更加底层,编译速度会更快,在编写内核时大多数都是C语言去写。 在C++中,命名空间(Namespace)是一种组织代码的方式,主要用于解决全局变量、函数或类的命名冲突问题。命名空间提供了一种封装机制,允许开发者将相关的类、函数、变量等放在一个逻辑上封闭的区域中,这样相同的名字在不同的命名空间中可以共存,而不会相互干扰。
|
5月前
|
Unix 编译器 C语言
【C++航海王:追寻罗杰的编程之路】关键字、命名空间、输入输出、缺省、重载汇总
【C++航海王:追寻罗杰的编程之路】关键字、命名空间、输入输出、缺省、重载汇总
27 0
|
5月前
|
编译器 C语言 C++
【C++】:C++关键字,命名空间,输入&输出,缺省参数
【C++】:C++关键字,命名空间,输入&输出,缺省参数
42 0