• 【C++】命名空间 namespace 与 标准流 iostream ( 命名空间概念简介 | 命名空间定义 | 命名空间使用 | iostream 中的命名空间分析 )






    一、命名空间 namespace




    1、命名空间基本概念


    命名空间 namespace 又称为 名字空间 , 名称空间 , 名域 , 作用域 , 是 C++ 语言 对 C 语言 的扩展 之一 ;

    C++ 中的 命名空间 namespace 指的是 标识符 的 可见范围 , C++ 标准库中的 所有 标识符 , 都定义在 std 命名空间中 ;


    2、名称概念


    命名空间 英文名称是 " namespace " , name 是 名字 , 名称 的意思 , space 空间 ; 这里的 名称 name 可以是

    • 符号常量 名称
    • 变量 名称
    • 宏定义 名称
    • 函数 名称
    • 结构体 名称
    • 枚举 名称
    • 类 名称
    • 对象 名称

    在命名空间中 , 可以定义上述 符号常量 , 变量 , 宏定义 , 函数 , 结构体 , 枚举 , 类 , 对象 等内容 ;

    命名空间 不是专门定义 标识符名称的 , 而是可以定义 C++ 中出现的所有语法元素 ;


    4、C 语言的命名空间


    在 C 语言中 , 只有一个命名空间 namespace , 就是 全局作用域 ;

    C 语言中 , 所有的 全局标识符 , 都共享 同一个 命名空间 namespace ( 作用域 / 名字空间 ) ;

    这就使得 , 在 C 语言开发中 , 标识符 定义 经常出现冲突 , 在 C 语言 的 大规模开发中 , 不同的团队 开发者之间不好协调 ;

    • 示例 1 : 开发者 A 定义了 全局变量 name , 开发者 B 也定义了 全局变量 name , 这就导致了二者之间出现了冲突 ;
    • 示例 2 : C 语言模块 1 中定义了 全局变量 name , 在 C 语言模块 2 中定义了相同名称的全局变量 name , 如果 主程序 同时导入了这两个模块 , 就出现了冲突 ;

    鉴于上述问题 , 在 C++ 中引入了新的概念 , 命名空间 namespace , 解决上述 标识符名称冲突的问题 ;


    3、命名空间避免标识符冲突


    C++ 被设计用于开发 大规模 的程序 , 参与开发的 开发者 或 团队 可能很多 , 每个开发者都要定义各种 变量 函数 类 对象 等 , 涉及到大量的 标识符 名称 ;

    为了避免名称冲突 , 引入了 命名空间 namespace 关键字 , 每个开发者将自己写的 名称 定义到 专门的空间中 , 这个空间就是 命名空间 namespace ;


    命名空间 namespace 可以避免 定义 各种 变量名称 / 函数名称 等名称时 , 出现 " 名称冲突 " 问题 ;

    在 命名空间 中 , 开发者可以 将 各种 常量 / 变量 / 宏定义 / 函数 / 结构体 / 枚举 / 类 / 对象 等 内容 , 组织在一起 , 避免与 其它 命名空间 或 全局标识符 发生冲突 ;


    命名空间 可以 将 整体的 全局作用于 切割成 不同的区域 , 也就是 不同的区域 使用 不同的 命名空间 ;

    不同的 命名空间 中 , 可以定义 相同名称的 标识符 , 不会出现冲突 ;

    C++ 中 的 默认命名空间是 全局作用域 , 访问 全局作用域 中的标识符 ,

    • 可以直接访问 ,
    • 也可以使用 ::标识符 进行访问 ;

    命名空间 是 可以嵌套的 , 可以在一个命名空间中 , 定义另外一个命名空间 ;


    C++ 的命名空间 可以理解为 Java 中的 包名 Package , 在不同的 Package 包 中 , 可以定义相同名称的 类 ;





    二、命名空间定义




    1、命名空间基本概念


    C++ 命名空间类型 :

    • 嵌套命名空间 :命名空间 中可以 嵌套 定义 另一个命名空间 , 内层 被 嵌套的 命名空间 可以进一步嵌套 ; 访问 嵌套 命名空间 标识符 , 需要将 不同层次 的 命名空间都写上 ;
    • 普通命名空间 : 标识符 独立 的 使用 范围 , 在 普通命名空间 中定义的标识符 , 可以在 其它命名空间 或 默认的全局命名空间 中使用 ;

    2、命名空间定义语法


    命名空间定义语法 : 定义 命名空间 需要使用 namespace 关键字 , 将要定义的内容 写在 namespace 命名空间名称 后的大括号中 ;

    namespace 命名空间名称 {  
        // 声明标识符  
        // 可以是 符号常量 , 变量 , 宏定义 , 函数 , 结构体 , 枚举 , 类 , 对象 等内容  
    }
    
    • 1
    • 2
    • 3
    • 4

    命名空间定义示例 :

    // 自定义命名空间
    namespace MyNamespace {
    	// 声明标识符  
    	int myVariable = 10;
    	void myFunction() {
    		// 函数体  
    		cout << "MyNamespace myFunction" << endl;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、代码示例 - 命名空间定义使用


    这里要特别注意 , 在下面的代码中 , 定义了 MyNamespace 命名空间 ,

    但是在该 文件 中没有使用 该 命名空间 , 那么如果要访问 命名空间 中的内容 , 需要添加 MyNamespace :: 前缀 ,

    访问 MyNamespace 命名空间中的 的 myVariable 变量 , 需要使用 MyNamespace::myVariable 代码访问 ;

    访问 MyNamespace 命名空间中的 的 myFunction 方法 , 需要使用 MyNamespace::myFunction() 代码访问 ;


    代码示例 :

    // 包含 C++ 头文件
    #include "iostream"
    
    // 使用 std 标准命名空间
    //		该命名空间中 , 定义了很多标准定义
    using namespace std;
    
    // 自定义命名空间
    namespace MyNamespace {
    	// 声明标识符  
    	int myVariable = 10;
    	void myFunction() {
    		// 函数体  
    		cout << "MyNamespace myFunction" << endl;
    	}
    }
    
    
    int main() 
    {
    	cout << "命名空间中的变量 : " << MyNamespace::myVariable << endl;
    	MyNamespace::myFunction(); // 调用命名空间中的函数 
    	
    	// 控制台暂停 , 按任意键继续向后执行
    	system("pause");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    执行结果 :

    命名空间中的变量 : 10
    MyNamespace myFunction
    Press any key to continue . . .
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    在这里插入图片描述





    三、命名空间使用




    1、命名空间默认访问方式


    如果不导入命名空间 std , 将 using namespace std; 代码注释掉 , 此时就会报错 , cin , cout , endl 都会报 " 未定义标识符 " 错误 ;

    在这里插入图片描述

    如果想要在 不声明 命名空间 的情况下 , 使用 标准流 中的标识符 , 就需要使用

    • std::cout
    • std::endl
    • std::cin

    否则 无法访问 这些 标识符;


    代码如下 : 在下面的代码中 , 没有声明全局命名空间 std , 要使用 iostream 中的标识符 , 必须加上 std:: 前缀 ;

    // 包含 C++ 头文件
    #include "iostream"
    
    // 使用 std 标准命名空间
    //		该命名空间中 , 定义了很多标准定义
    //using namespace std;
    
    int main()
    {
    	// 定义圆半径 , 周长 , 面积 对应的变量
    	double r = 0, p = 0, a = 0;
    
    	// 提示输入圆半径
    	std::cout << "输入圆半径 :" << std::endl;
    
    	// 从命令行标准输入得到的数据 到 变量 r 指示的内存空间中
    	std::cin >> r;
    	std::cout << "接收到圆半径 :" << r << std::endl;
    
    	// 计算圆周长
    	p = 3.14159 * 2 * r;
    
    	// 计算圆面积
    	a = 3.14159 * r * r;
    
    	// 打印计算结果
    	std::cout << "圆周长为 :" << p << " 圆面积为 : " << a << std::endl;
    
    
    	// 控制台暂停 , 按任意键继续向后执行
    	system("pause");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    执行结果 :

    输入圆半径 :
    10
    接收到圆半径 :10
    圆周长为 :62.8318 圆面积为 : 314.159
    请按任意键继续. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


    2、使用命名空间


    使用命名空间 语法 : 使用如下语法 , 可以 声明使用一个命名空间 , 可以直接访问命名空间中的元素 ;

    // 使用 指定的 命名空间
    using namespace 命名空间名称;
    
    • 1
    • 2

    如果要使用 嵌套的命名空间 , 如 : 命名空间 A 中定义 命名空间 B , 命名空间 B 中定义了 命名空间 C , 则使用如下语法 :

    // 使用 指定的 嵌套 命名空间
    using namespace A::B::C;
    
    • 1
    • 2

    之前的章节中 , 自定义了 命名空间 MyNamespace ,

    // 自定义命名空间
    namespace MyNamespace {
    	// 声明标识符  
    	int myVariable = 10;
    	void myFunction() {
    		// 函数体  
    		cout << "MyNamespace myFunction" << endl;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    但是 , 使用时 , 必须通过 MyNamespace::myVariable 的形式访问 命名空间 中的变量 ;

    如果想要 直接访问命名空间元素 , 可以使用上述 语法 , 导入命名空间 :

    // 使用自定义的命名空间
    // 注意 : 使用命名空间需要在 定义命名空间之后
    using namespace MyNamespace;
    
    • 1
    • 2
    • 3

    注意 : 使用 命名空间 需要在 定义命名空间之后 , 否则会报错 ;


    3、使用默认的命名空间


    当前的 全局命名空间 就是 默认的 命名空间 , 如果你 没有在 命名空间 中定义 变量 / 类 / 函数 等元素 , 而是 直接在 C++ 代码中直接定义 , 那么这些元素 就是 定义在了 默认的 命名空间 中 ;

    将变量定义在 C++ 代码中 , 就是定义了 全局空间变量 , 就是 默认命名空间 中的变量 ;

    调用 默认命名空间 中的变量 , 可以使用 :: 前缀访问 ;


    代码示例 :

    // 包含 C++ 头文件
    #include "iostream"
    
    // 将变量 定义在了 默认命名空间 : 全局命名空间
    int globalVariable = 10;
    
    // 将函数 定义在了 默认命名空间 : 全局命名空间
    void globalFunction() {
    	std::cout << "globalFunction" << std::endl;
    }
    
    int main() {
    	::globalFunction();		// 调用全局函数 默认命名空间中的函数  
    	::globalVariable = 20;  // 修改全局变量 默认命名空间中的变量
    	std::cout << "::globalVariable : " << ::globalVariable << std::endl;
    
    	// 调用 默认命名空间 中的元素 , 不加域操作符也可以使用
    	globalFunction();		// 调用全局函数 默认命名空间中的函数  
    	globalVariable = 30;    // 修改全局变量 默认命名空间中的变量
    	std::cout << "globalVariable : " << globalVariable << std::endl;
    
    	// 控制台暂停 , 按任意键继续向后执行
    	system("pause");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    执行结果 :

    globalFunction
    ::globalVariable : 20
    globalFunction
    globalVariable : 30
    Press any key to continue . . .
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    在这里插入图片描述


    4、代码示例 - 使用命名空间


    完整代码示例 :

    // 包含 C++ 头文件
    #include "iostream"
    
    // 使用 std 标准命名空间
    //		该命名空间中 , 定义了很多标准定义
    using namespace std;
    
    // 自定义命名空间
    namespace MyNamespace {
    	// 声明标识符  
    	int myVariable = 10;
    	void myFunction() {
    		// 函数体  
    		cout << "MyNamespace myFunction" << endl;
    	}
    }
    
    // 使用自定义的命名空间
    // 注意 : 使用命名空间需要在 定义命名空间之后
    using namespace MyNamespace;
    
    
    int main() 
    {
    	cout << "命名空间中的变量 : " << myVariable << endl;
    	myFunction(); // 调用命名空间中的函数 
    	
    	// 控制台暂停 , 按任意键继续向后执行
    	system("pause");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    执行结果 :

    命名空间中的变量 : 10
    MyNamespace myFunction
    Press any key to continue . . .
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    在这里插入图片描述





    四、标准流 iostream



    标准流 iostream 的内容 , 都定义在 std 命名空间中 ;

    C++ 语言为了与 C 语言 在 头文件上 进行区分

    • C++ 语言的头文件没有 .h 后缀 ;
    • C 语言的头文件有 .h 后缀 ;

    1、查看 iostream 头文件


    在代码中 , " Ctrl + 左键 " 点击 iostream 头文件 , 即可 跳转到该 标准流 头文件中 ;
    在这里插入图片描述

    在 Visual Studio 2019 中的 解决方案资源管理器 中 , 双击展开 外部依赖项 ,

    在这里插入图片描述

    向下翻 , 就可以找到 iostream 头文件 ,

    在这里插入图片描述


    2、iostream 头文件源码


    iostream 头文件 , 只有 60 行代码 , 核心的内容都定义在 yvals_core.h 和 istream 头文件中 ;

    在 该头文件 中 , 第 19 行使用了 _STD_BEGIN 宏定义 , 相当于定义 namespace std { 命名空间的开始 , 最后的第 53 行使用的 _STD_END 宏 相当于 命名空间的 定义结束 } ;

    // iostream standard header
    
    // Copyright (c) Microsoft Corporation.
    // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
    
    #pragma once
    #ifndef _IOSTREAM_
    #define _IOSTREAM_
    #include 
    #if _STL_COMPILER_PREPROCESSOR
    #include 
    
    #pragma pack(push, _CRT_PACKING)
    #pragma warning(push, _STL_WARNING_LEVEL)
    #pragma warning(disable : _STL_DISABLED_WARNINGS)
    _STL_DISABLE_CLANG_WARNINGS
    #pragma push_macro("new")
    #undef new
    _STD_BEGIN // 开始定义 std 命名空间
    #ifdef _M_CEE_PURE
    __PURE_APPDOMAIN_GLOBAL extern istream cin, *_Ptr_cin;
    __PURE_APPDOMAIN_GLOBAL extern ostream cout, *_Ptr_cout;
    __PURE_APPDOMAIN_GLOBAL extern ostream cerr, *_Ptr_cerr;
    __PURE_APPDOMAIN_GLOBAL extern ostream clog, *_Ptr_clog;
    
    __PURE_APPDOMAIN_GLOBAL extern wistream wcin, *_Ptr_wcin;
    __PURE_APPDOMAIN_GLOBAL extern wostream wcout, *_Ptr_wcout;
    __PURE_APPDOMAIN_GLOBAL extern wostream wcerr, *_Ptr_wcerr;
    __PURE_APPDOMAIN_GLOBAL extern wostream wclog, *_Ptr_wclog;
    
    #else // _M_CEE_PURE
          // OBJECTS
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT istream cin, *_Ptr_cin;
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT ostream cout, *_Ptr_cout;
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT ostream cerr, *_Ptr_cerr;
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT ostream clog, *_Ptr_clog;
    
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT wistream wcin, *_Ptr_wcin;
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT wostream wcout, *_Ptr_wcout;
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT wostream wcerr, *_Ptr_wcerr;
    __PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT wostream wclog, *_Ptr_wclog;
    
    // CLASS _Winit
    class _CRTIMP2_PURE_IMPORT _Winit {
    public:
        __thiscall _Winit();
        __thiscall ~_Winit() noexcept;
    
    private:
        __PURE_APPDOMAIN_GLOBAL static int _Init_cnt;
    };
    #endif // _M_CEE_PURE
    _STD_END // 结束定义 std 命名空间
    #pragma pop_macro("new")
    _STL_RESTORE_CLANG_WARNINGS
    #pragma warning(pop)
    #pragma pack(pop)
    #endif // _STL_COMPILER_PREPROCESSOR
    #endif // _IOSTREAM_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    3、yvals_core.h 头文件中 std 命名空间相关宏定义


    在 yvals_core.h 头文件中 , 定义了 std 命名空间相关的宏定义 , 如 : _STD_BEGIN , _STD_END , _STD 等 ;

    // NAMESPACE
    #define _STD_BEGIN namespace std {
    #define _STD_END }
    #define _STD ::std::
    
    • 1
    • 2
    • 3
    • 4

    4、iostream 使用时一般导入 std 命名空间


    在 C++ 代码中 , 经常见到 下面两行代码 在一起使用 ,

    使用 C++ 的 iostream 标准流时 , 需要使用 #include "iostream" 代码先导入该标准库 ;

    由于 iostream 头文件中没有定义 全局命名空间 , 如果要使用 cin 或者 cout , 必须加上 std:: 前缀 , 如 : std::cinstd::cout ;

    // 包含 C++ 头文件
    #include "iostream"
    
    // 使用 std 标准命名空间
    //		该命名空间中 , 定义了很多标准定义
    using namespace std;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    力扣第108题 将有序数组转二叉搜索树 c++
    autopoi-web 导出 excel 自定义样式
    【计算机组成原理笔记】总线
    .net生鲜超市销售系统
    Android 11.0 Launcher3桌面显示多个相同app图标的解决办法
    python使用opencv实现火焰检测
    mockjs学习
    Linux下自动挂载U盘或者USB移动硬盘
    umi项目本地开发环境远程打开的问题
    Vue3 从入门到放弃 (第二篇.创建第一个Web应用)
  • 原文地址:https://blog.csdn.net/han1202012/article/details/132342726