C++从入门到精通——命名空间

这篇具有很好参考价值的文章主要介绍了C++从入门到精通——命名空间。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

命名空间是一种用于封装和组织代码的结构,可以避免名称冲突并提供更好的代码组织性。在编程中,命名空间通常用于将相关的类、函数、变量等组织在一起,形成一个独立的逻辑单元。通过使用命名空间,可以更加清晰地组织代码,提高代码的可读性和可维护性。同时,命名空间也可以用于控制访问权限,保护代码的安全性和稳定性。因此,在编程中,合理地使用命名空间是一种重要的编程实践。


一、命名空间

引例

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main()
{
 	printf("%d\n", rand);
 	return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

C++从入门到精通——命名空间,C++从入门到精通,c++,开发语言,c语言,visual studio,后端,学习方法,考研
为什么会出现这种情况呢?是因为在C语言中的stdlib.h中的rand函数和我们定义的变量冲突了,这种情况在C语言中我们只能通过改变参数的名字来解决这种情况,但是在C++完全不用担心这种情况,因为C++中有着命名空间namespace来严格管控函数

什么是命名空间

命名空间顾名思义就是通过定义一个空间来封装变量,函数,是一种用来给变量和函数等标识符起一个独特且有组织的名称的机制。通过使用命名空间,可以避免在不同的代码模块中出现重名的标识符,从而提高代码的可读性和可维护性。

namespace bit
{
		……
}

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

命名空间是一个用于封装类、函数、变量等代码元素的容器,它提供了一种将相关代码组织在一起的方式,并避免了不同代码之间的命名冲突。在编程中,命名空间的存在使得代码更加清晰、有序,提高了代码的可读性和可维护性。

在C++语言中,命名空间的使用尤为普遍。通过使用命名空间,我们可以将不同模块的代码分隔开来,避免了函数和变量名称的冲突。例如,在C++标准库中,所有的标准函数和类都被定义在一个名为std的命名空间中,这样我们在使用标准库时就需要通过std::前缀来访问其中的元素。

除了C++,其他编程语言也提供了类似命名空间的机制。例如,在Python中,我们可以通过模块来实现类似命名空间的功能。每个模块都是一个独立的命名空间,其中包含了该模块中定义的所有函数、类和变量。当我们在其他模块中导入某个模块时,就可以通过该模块的名称来访问其中的元素,从而避免了命名冲突。

命名空间的使用不仅可以提高代码的可读性和可维护性,还可以帮助我们更好地组织和管理代码。通过将相关的代码元素放在同一个命名空间中,我们可以更加清晰地表达代码之间的逻辑关系,使得代码更加易于理解和维护。

在实际开发中,我们应该充分利用命名空间的特性,合理地组织和管理代码。同时,我们也需要注意避免过度使用命名空间,以免造成代码结构的混乱和复杂性的增加。只有在适当的时候使用命名空间,才能更好地发挥其优势,提高代码的质量和效率。

二、命名空间定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。

ps:下文中的bit是我自己定义的,不是只能这样定义,也可以换成其他名称,名称根据自己的喜好定义即可,如果是在项目中,可以按照项目名称来定义

正常的命名空间定义

namespace bit
{
	// 命名空间中可以定义变量/函数/类型
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}

嵌套的命名空间

//命名空间可以嵌套
namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}

多个相同名称的命名空间

同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}
namespace N1
{
	int Mul(int left, int right)
	{
		return left * right;
	}
}

上面相同的命名空间将在代码的运行过程中变成下述情况(当然实际的在编译运行的时候肯定不是这样的,但实际意义是一样的,读者可以按照下述来理解)

namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
	int Mul(int left, int right)
	{
	return left * right;
	}
}

注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

在全局和命名空间定义相同的结构体

在C语言中,可以在全局作用域和命名空间中同时定义相同的结构体,但是它们是不同的结构体类型。这是因为全局作用域中的结构体类型在整个程序中是可见的,而命名空间中的结构体类型只在该命名空间内可见。

下面是一个例子:

#include <iostream>

struct MyStruct {
    int x;
};

namespace Namespace {
    struct MyStruct {
        int y;
    };
}

int main() {
    struct MyStruct globalStruct;
    Namespace::MyStruct namespaceStruct;

    globalStruct.x = 10;
    namespaceStruct.y = 20;

    std::cout << "Global struct x: " << globalStruct.x << std::endl;
    std::cout << "Namespace struct y: " << namespaceStruct.y << std::endl;

    return 0;
}

在上面的例子中,我们在全局作用域中定义了一个名为MyStruct的结构体,它有一个整型成员x。然后,在命名空间Namespace中定义了另一个名为MyStruct的结构体,它有一个整型成员y

main函数中,我们创建了一个全局作用域的MyStruct类型的变量globalStruct,以及一个命名空间Namespace中的MyStruct类型的变量namespaceStruct。然后,我们分别为它们的成员变量赋值,并打印输出它们的值。

运行上述代码,输出结果如下:

Global struct x: 10
Namespace struct y: 20

可以看到,全局作用域的MyStruct和命名空间Namespace中的MyStruct是两个不同的结构体类型。它们的成员变量分别是xy,并且互不干扰。

直接展开命名空间会出现的问题

但是如果直接展开命名空间,就会出现报错,即报错的原因是因为在直接展开命名空间时,编译器无法区分全局作用域中的结构体和命名空间作用域中的结构体。因此,当遇到相同的结构体名称时,编译器无法确定应该使用哪个定义。

下面是一个示例,演示了直接展开命名空间时出现的错误:

struct MyStruct {
    int data;
};

namespace MyNamespace {
    struct MyStruct {
        int data;
    };
}
using namespace MyNamespace;
int main() {
    MyStruct structVar; // 错误!编译器无法确定是全局结构体还是命名空间中的结构体

    return 0;
}

C++从入门到精通——命名空间,C++从入门到精通,c++,开发语言,c语言,visual studio,后端,学习方法,考研

在上述示例中,当我们直接使用 MyStruct 来定义结构体变量 structVar 时,编译器无法确定是要使用全局结构体还是命名空间中的结构体。因此,编译器会报错并提示二义性。

解决办法

为了避免这种二义性,我们可以使用命名空间限定符来明确指定要使用的结构体,如前面的回答中所示。

这种情况下,我们可以使用命名空间限定符来区分全局和命名空间中定义的相同结构体。命名空间限定符的格式为 命名空间名称::结构体名称

例如,假设我们有一个全局定义的结构体 MyStruct,同时在命名空间 MyNamespace 中也定义了一个同名的结构体 MyStruct。如果我们想要在全局作用域中访问全局结构体,可以使用 ::(全局作用域运算符)来限定它的命名空间,如下所示:

struct MyStruct {
    int data;
};

namespace MyNamespace {
    struct MyStruct {
        int data;
    };
}

int main() {
    MyStruct globalStruct; // 访问全局结构体
    MyNamespace::MyStruct namespaceStruct; // 访问命名空间中的结构体

    return 0;
}

在上述示例中,MyStruct 是全局结构体,而 MyNamespace::MyStruct 是命名空间中的结构体。我们可以使用相应的限定符来访问它们。

三、命名空间使用

命名空间中成员该如何使用呢?

比如:

namespace bit
{
	// 命名空间中可以定义变量/函数/类型
	int a = 0;
	int b = 1;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
int main()
{
	// 编译报错:error C2065: “a”: 未声明的标识符
	printf("%d\n", a);
	return 0;
}

C++从入门到精通——命名空间,C++从入门到精通,c++,开发语言,c语言,visual studio,后端,学习方法,考研
为什么会出现报错呢?是因为a已经被放到我们定义的namespace bit中了,编译器直接查找的话是查找不到的

在这里我涉及一些编译器查找的知识,我们在同时定义一个变量的全局变量和局部变量

int a = 0;
int main()
{
	int a = 1;
	// 编译报错:error C2065: “a”: 未声明的标识符
	printf("%d\n", a);
	return 0;
}

C++从入门到精通——命名空间,C++从入门到精通,c++,开发语言,c语言,visual studio,后端,学习方法,考研
我们可以明显看到编译器打印了局部变量,之所以打印局部变量是因为编译器查找是按照

  • 局部变量
  • 全局变量

这两种情况来查找的,正常情况下是没有namespace的访问权利的,我们需要通过代码来获得访问权利,即使编译器查找变成

  • 局部变量
  • 全局变量
  • namespace

ps:命名空间里的未赋值的变量是随机值吗?
在许多编程语言中,命名空间中未赋值的变量通常被初始化为默认值,而不是随机值。这些默认值可能是零、空、false或null,具体取决于编程语言和变量的类型。对于数字类型的变量,通常将其初始化为零或null。对于布尔类型的变量,通常将其初始化为false。对于字符串类型的变量,通常将其初始化为空字符串。对于对象类型的变量,通常将其初始化为null。这样可以确保在使用变量之前,它们都有一个已定义的值,从而避免出现随机的不确定性。

命名空间的使用有三种方式:

加命名空间名称及作用域限定符

ps:我们可以printf("%d\n", ::a);这样a是全局变量

int main()
{
    printf("%d\n", N::a);
    //打印嵌套命名空间printf("%d\n", N::N1::a);
    return 0;    
}

这样打印的是名称为N命名空间里的a变量

带有结构体的命名空间定义结构体变量

下面是一个示例,展示了如何在命名空间中定义带有结构体的结构体变量:

#include <iostream>

namespace MyNamespace {
    struct MyStruct {
        int value;
    };
}

int main() {
    using namespace std;
    MyNamespace::MyStruct myVar;
    //也可以是下述情况
    struct MyNamespace::MyStruct n1;
    //不能是MyNamespace::struct MyStruct myVar;
    myVar.value = 10;
    n1.value = 20;
    cout << myVar.value << endl;
    cout << n1.value << endl;
    return 0;
}

C++从入门到精通——命名空间,C++从入门到精通,c++,开发语言,c语言,visual studio,后端,学习方法,考研

注意,在使用结构体变量时,我们需要使用作用域解析运算符::来指定结构体所属的命名空间。

使用using将命名空间中某个成员引入

直接使用using可以便于不需要每次都打印N::b

using N::b;
int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    return 0;    
}

使用using namespace 命名空间名称引用

直接引用NN会成为上述所说的第三查找标准

using namespce N;
int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    Add(10, 20);
    return 0;    
}

引用命名空间和引用头文件有什么区别

在C++编程中,引用命名空间和引用头文件是两个常见的概念,它们各自承担着不同的角色,并在编程过程中发挥着不可或缺的作用。虽然它们都与代码的组织和重用有关,但它们的用途和效果却有所不同。

首先,引用命名空间(using namespace)主要是为了解决命名冲突和简化代码书写。在大型项目中,不同的库和模块可能会使用相同的名称来命名不同的函数或类。为了避免这种命名冲突,C++引入了命名空间的概念。通过引用命名空间,我们可以告诉编译器我们希望使用哪个命名空间中的名称,从而避免因为名称冲突而导致的编译错误。例如,当我们在代码中写using namespace std;时,我们就告诉编译器我们想使用标准库中的所有名称,而不需要在每次调用标准库函数或类时都加上std::前缀。

而引用头文件(#include)则是C++中实现代码重用和模块化编程的重要手段。头文件通常包含了类的声明、函数的原型、常量定义等,它们可以被多个源文件共享和引用。通过引用头文件,我们可以实现代码的模块化,使得每个模块只关心自己的功能实现,而不必关心其他模块的实现细节。这样不仅可以提高代码的可读性和可维护性,还可以提高编译效率,因为编译器只需要编译那些被实际引用的头文件和源文件。

虽然引用命名空间和引用头文件在C++编程中有着不同的作用,但它们在实际应用中往往是相辅相成的。例如,在一个头文件中,我们可能会定义一些属于特定命名空间的函数或类。当其他源文件需要使用这些函数或类时,它们不仅需要引用这个头文件,还需要引用相应的命名空间。这样,通过引用头文件和命名空间,我们就可以在不同的源文件之间共享和重用代码,同时避免命名冲突和简化代码书写。

综上所述,引用命名空间和引用头文件在C++编程中各有其独特的作用。引用命名空间主要用于解决命名冲突和简化代码书写,而引用头文件则主要用于实现代码重用和模块化编程。通过合理地使用它们,我们可以编写出更加高效、可读和可维护的C++代码。文章来源地址https://www.toymoban.com/news/detail-845615.html

四、测试代码展示

namespace.cpp

#include <stdio.h>
//#include <stdlib.h>
//int rand = 10;
 C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
//int main()
//{
//    printf("%d\n", rand);
//    return 0;
//}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”
//#include<iostream>
//using namespace std;

//  正常的命名空间定义
namespace bit
{
	// 命名空间中可以定义变量/函数/类型
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
//命名空间可以嵌套
namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}
namespace N1
{
	int Mul(int left, int right)
	{
		return left * right;
	}
}
//namespace bit
//{
//	// 命名空间中可以定义变量/函数/类型
//	int a = 0;
//	int b = 1;
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//	struct Node
//	{
//		struct Node* next;
//		int val;
//	};
//}

struct MyStruct {
	int data;
};

namespace MyNamespace {
	struct MyStruct {
		int data;
	};
}
//using namespace MyNamespace;
int main() {
	MyStruct structVar; // 错误!编译器无法确定是全局结构体还是命名空间中的结构体

	return 0;
}
//int main()
//{
//
//	// 编译报错:error C2065: “a”: 未声明的标识符
//	printf("%d\n", N1::a);
//	return 0;
//}
//int main()
//{
//	using namespace bit;
//	using std::cout;
//	using std::cin;
//	int i, j;
//	cout << "hello world" << "!" << std::endl;
//	cin >> i >> j;
//	cout << i + j<<std::endl;
//}

到了这里,关于C++从入门到精通——命名空间的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】入门 --- 命名空间

    本篇文章是《C++ 初阶》 专栏的第一篇文章,从本专栏开始就进入了C++的学习了哦!本篇的内容是C++入门:命名空间的学习希望烙铁们可以理解消化哦🥰!!! 🚩C++是一种计算机高级程序设计语言,由C语言扩展升级而产生 ,最早于1979年由 本贾尼·斯特劳斯特卢普在ATT贝尔

    2024年02月16日
    浏览(33)
  • 【Visual Studio】报错 C2653,使用 C++ 语言,配合 Qt 开发串口通信界面

    知识不是单独的,一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏:Visual Studio。 这个 Bug 是我做这个工程时遇到的:【Visual Studio】Qt 的实时绘图曲线功能,使用 C++ 语言,配合 Qt 开发串口通信界面。 使用 C++ 语言,配合 Qt 开发串口通信界面,在添加 Widget 做

    2024年02月11日
    浏览(55)
  • C++入门:命名空间与输入输出

    目录 1.命名空间 1.1 命名空间的定义 1.2 命名空间的使用 1.3 标准命名空间 std 2.C++输入输出 我们在初学C++时,经常会在代码开头看到这样的一行代码: 这行代码到底什么意思呢?我们学完命名空间就可以理解了。 在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些

    2024年02月11日
    浏览(46)
  • 『C++成长记』C++入门——命名空间&缺省参数

     🔥 博客主页: 小王又困了 📚 系列专栏: C++ 🌟 人之为学,不日近则日退 ❤️ 感谢大家点赞👍收藏⭐评论✍️ 目录 一、C++的认识 📒1.1什么是C++ 📒1.2C++的发展 二、C++ 三、命名空间 📒3.1为什么有命名空间 📒3.2命名空间定义 📒3.3命名空间使用 📒3.4命名空间的

    2024年02月08日
    浏览(37)
  • 【C++入门系列】——命名空间和输入输出

    📚lovewold少个r博客主页     ⚠️ 本文重点 : c++入门第一个程序和基本知识讲解 😄 每日一言 :忙,不会死,人只有越忙越活,流水不腐,户枢不蠹。 ​作者主页 前言 谈谈我个人对语言和职业的看法 C++的历史发展 C++第一个程序 命名空间 定义命名空间 使用此命名空间 命

    2024年02月05日
    浏览(45)
  • 【C++初阶】C++入门——C++介绍、命名空间、输入输出

     C语言是 结构化 和 模块化 的语言,适合处理 较小规模 的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机,20世纪80年代,计算机界提出了 OOP (object oriented programming: 面向对象 )思想,支持面向对象的程序设计语言应

    2024年02月11日
    浏览(43)
  • 【Visual Studio】Qt 的实时绘图曲线功能,使用 C++ 语言,配合 Qt 开发串口通信界面

    知识不是单独的,一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏:Visual Studio。 战斗背景:做了个串口接收界面,用来接收传输过来的信号。但是光用数字显示太单调,需要用图线显示出来。 战略目标:干掉它。 战术路线:Qt 绘图可以使用 Qt Charts,先了解

    2024年02月11日
    浏览(52)
  • C++入门 上(命名空间 缺省参数 函数重载)

    在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace的出现就是针对这种问题的。 定义命名空间

    2024年02月19日
    浏览(47)
  • VSIX:C#项目 重命名所有标识符(Visual Studio扩展开发)

            出于某种目的(合法的,真的合法的,合同上明确指出可以这样做),我准备了一个重命名所有标识符的VS扩展,用来把一个C#库改头换面,在简单的测试项目上工作很满意,所有标识符都被准确替换。我还尝试用在C++项目上,问题就比较多了,因为VS并不能准确识别

    2024年02月05日
    浏览(56)
  • 【C++学习】C++入门 | C++该怎么学 | 命名空间 | 输入输出

    欢迎来到C++的世界,这是一门令人兴奋的语言。 好吧,每当我开始阅读C++的书籍的时候,开头的第一句话必定是这个, 也不知道其他语言的编程书籍是不是这样,那就让这句话也作为我C++分享之路上的第一句话吧。 目录 写在前面 1. C++怎么学? 1. C语言 2. Object-Oriented C++ 3.

    2024年02月10日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包