Bootstrap

C++从入门到实战(二)C++命名空间


前言

  • 上一节我们介绍了 C++ 的历史,对这门强大编程语言的发展脉络有了清晰认识。这一节我们将围绕着 C++ 的第一个程序,深入探讨 C++ 的命名空间。理解命名空间对于我们编写大型、复杂且结构清晰的 C++ 程序至关重要。

一、C++的第一个程序

  • 在 C++ 中,经典的第一个程序通常是 “Hello, World!” 程序。下面是该程序的代码示例:
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

在这段代码中

#include <iostream> 是预处理指令,这个头文件提供了输入输出流的功能,比如 cout 用于输出。

std::cout << "Hello, World!" << std::endl; 这行代码用于在控制台输出 “Hello, World!”。

std::cout 是标准输出流对象,<< 是流插入运算符,

std::endl 用于换行并刷新缓冲区

二、命名空间

在这里插入图片描述

(一)为什么需要命名空间

  • 随着项目规模的扩大,代码中会定义大量的变量、函数和类等标识符。
  • 不同的库或者模块可能会使用相同的标识符名称,这就会导致命名冲突。
  • 例如,两个不同的库都定义了一个名为 print 的函数,如果同时使用这两个库,编译器就无法确定调用哪个 print 函数

命名空间就是为了解决这个问题而引入的。

  • 它可以将全局作用域划分为不同的逻辑区域,每个区域内的标识符相互独立,避免命名冲突。

(二)定义命名空间

  • 在 C++ 中,可以使用 namespace 关键字来定义命名空间。例如:
namespace MyNamespace {
    int value = 10;
    void print() {
        std::cout << "This is in MyNamespace. Value is: " << value << std::endl;
    }
}

在上述代码中,定义了一个名为 MyNamespace 的命名空间,在这个命名空间内定义了一个变量 value 和一个函数 print。

(三)使用命名空间

1.通过命名空间限定符:

  • 要使用命名空间内的成员,可以使用命名空间限定符 ::
#include <stdio.h>
#include <stdlib.h>
namespace bit
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}

int main()
{
	printf("%d\n", bit::rand);
}

2.使用 using 声明:

  • 可以使用 using 声明来引入命名空间中的特定成员。
  • 也可以展开命名空间
2.1展开命名空间
  • 如果将展开命名空间理解为让命名空间内所有成员都能像在全局作用域一样直接使用,那么using namespace语句更符合这一描述。
namespace MyNamespace {
    int value = 10;
    void print() {
        std::cout << "Value is: " << value << std::endl;
    }
}

using namespace MyNamespace;

int main() {
    print();
    std::cout << "Value: " << value << std::endl;
    return 0;
}

在这里,using namespace MyNamespace;使得MyNamespace中的所有成员(value和print函数)都可以直接在main函数中使用,就好像它们是在全局作用域中定义的一样。

2.2使用 using namespace
namespace MyNamespace {
    int value = 10;
    void print() {
        std::cout << "Value is: " << value << std::endl;
    }
}

using MyNamespace::print;

int main() {
    print();
    // std::cout << "Value: " << value << std::endl; 
    // 这行代码会报错,因为value未通过using声明引入
    return 0;
}

在这个例子中,using MyNamespace::print;仅引入了print函数,因此只能直接使用print函数,而不能直接使用MyNamespace中的value变量。这表明using声明并没有像展开命名空间那样让所有成员都能直接使用,而是精确地引入指定成员

在这里插入图片描述

(四)嵌套命名空间

  • 命名空间可以嵌套定义:
namespace OuterNamespace {
    namespace InnerNamespace {
        int nestedValue = 20;
        void nestedPrint() {
            std::cout << "This is in InnerNamespace. Nested value is: " << nestedValue << std::endl;
        }
    }
}
  • 使用嵌套命名空间内的成员时,需要使用多层命名空间限定符:
int main() {
    std::cout << "Nested value: " << OuterNamespace::InnerNamespace::nestedValue << std::endl;
    OuterNamespace::InnerNamespace::nestedPrint();
    return 0;
}

(五)标准命名空间 std

  • 在 C++ 中,std 是标准命名空间

  • 几乎所有的标准库函数和类型都定义在这个命名空间内,比如前面提到的 cout、endl 等。

  • 通常我们使用标准库时,会通过std::来限定,如 std::cout。

  • 也可以使用 using 声明或 using namespace std; 来简化使用

全局使用 using namespace std; 要谨慎。

全局使用 using namespace std; 要谨慎。

全局使用 using namespace std; 要谨慎。

  • 1. 命名冲突风险

C++ 标准库 std 包含大量的标识符,如类型(std::string、std::vector)、函数(std::cout、std::sort)和模板(std::map、std::unique_ptr)等。当在全局使用 using namespace std; 后,这些标识符都被引入到全局作用域。如果项目中也定义了与标准库同名的标识符,就会引发命名冲突。

  • 2. 可读性降低
  • 使用 using namespace std; 后,代码中直接使用标准库的标识符,无法直观地判断该标识符是来自标准库还是其他自定义命名空间。这对于阅读代码的人来说,尤其是对代码库不熟悉的人,增加了理解难度

相比之下,使用 std:: 前缀,如 std::vector numbers;,可以清晰地表明 vector 是标准库中的类型。


以上就是这篇博客的全部内容,下一篇我们将继续探索 C++ 的更多精彩内容。

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述

;