【C++】定名空间 namespace 与 标准流 iostream ( 定名空间概念简介 | 定名 ...

打印 上一主题 下一主题

主题 1013|帖子 1013|积分 3039

一、定名空间 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 定名空间名称 后的大括号中 ;
  1. namespace 命名空间名称 {  
  2.     // 声明标识符  
  3.     // 可以是 符号常量 , 变量 , 宏定义 , 函数 , 结构体 , 枚举 , 类 , 对象 等内容  
  4. }
复制代码
定名空间定义示例 :
  1. // 自定义命名空间
  2. namespace MyNamespace {
  3.         // 声明标识符  
  4.         int myVariable = 10;
  5.         void myFunction() {
  6.                 // 函数体  
  7.                 cout << "MyNamespace myFunction" << endl;
  8.         }
  9. }
复制代码

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


这里要特别注意 , 在下面的代码中 , 定义了 MyNamespace 定名空间 ,
但是在该 文件 中没有使用 该 定名空间 , 那么如果要访问 定名空间 中的内容 , 必要添加 MyNamespace :: 前缀 ,
访问 MyNamespace 定名空间中的 的 myVariable 变量 , 必要使用 MyNamespace::myVariable 代码访问 ;
访问 MyNamespace 定名空间中的 的 myFunction 方法 , 必要使用 MyNamespace::myFunction() 代码访问 ;

代码示例 :
  1. // 包含 C++ 头文件
  2. #include "iostream"
  3. // 使用 std 标准命名空间
  4. //                该命名空间中 , 定义了很多标准定义
  5. using namespace std;
  6. // 自定义命名空间
  7. namespace MyNamespace {
  8.         // 声明标识符  
  9.         int myVariable = 10;
  10.         void myFunction() {
  11.                 // 函数体  
  12.                 cout << "MyNamespace myFunction" << endl;
  13.         }
  14. }
  15. int main() {        cout << "定名空间中的变量 : " << MyNamespace::myVariable << endl;        MyNamespace::myFunction(); // 调用定名空间中的函数                 // 控制台暂停 , 按恣意键继续向后执行        system("pause");}
复制代码
执行结果 :
  1. 命名空间中的变量 : 10
  2. MyNamespace myFunction
  3. Press any key to continue . . .
复制代码






三、定名空间使用




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


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

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


  • std::cout
  • std::endl
  • std::cin
否则 无法访问 这些 标识符;

代码如下 : 在下面的代码中 , 没有声明全局定名空间 std , 要使用 iostream 中的标识符 , 必须加上 std:: 前缀 ;
  1. // 包含 C++ 头文件
  2. #include "iostream"
  3. // 使用 std 标准命名空间
  4. //                该命名空间中 , 定义了很多标准定义
  5. //using namespace std;
  6. int main()
  7. {
  8.         // 定义圆半径 , 周长 , 面积 对应的变量
  9.         double r = 0, p = 0, a = 0;
  10.         // 提示输入圆半径
  11.         std::cout << "输入圆半径 :" << std::endl;
  12.         // 从命令行标准输入得到的数据 到 变量 r 指示的内存空间中
  13.         std::cin >> r;
  14.         std::cout << "接收到圆半径 :" << r << std::endl;
  15.         // 计算圆周长
  16.         p = 3.14159 * 2 * r;
  17.         // 计算圆面积
  18.         a = 3.14159 * r * r;
  19.         // 打印计算结果
  20.         std::cout << "圆周长为 :" << p << " 圆面积为 : " << a << std::endl;
  21.         // 控制台暂停 , 按任意键继续向后执行
  22.         system("pause");
  23. }
复制代码
执行结果 :
  1. 输入圆半径 :
  2. 10
  3. 接收到圆半径 :10
  4. 圆周长为 :62.8318 圆面积为 : 314.159
  5. 请按任意键继续. . .
复制代码


2、使用定名空间


使用定名空间 语法 : 使用如下语法 , 可以 声明使用一个定名空间 , 可以直接访问定名空间中的元素 ;
  1. // 使用 指定的 命名空间
  2. using namespace 命名空间名称;
复制代码
如果要使用 嵌套的定名空间 , 如 : 定名空间 A 中定义 定名空间 B , 定名空间 B 中定义了 定名空间 C , 则使用如下语法 :
  1. // 使用 指定的 嵌套 命名空间
  2. using namespace A::B::C;
复制代码

之前的章节中 , 自定义了 定名空间 MyNamespace ,
  1. // 自定义命名空间
  2. namespace MyNamespace {
  3.         // 声明标识符  
  4.         int myVariable = 10;
  5.         void myFunction() {
  6.                 // 函数体  
  7.                 cout << "MyNamespace myFunction" << endl;
  8.         }
  9. }
复制代码
但是 , 使用时 , 必须通过 MyNamespace::myVariable  的形式访问 定名空间 中的变量 ;
如果想要 直接访问定名空间元素 , 可以使用上述 语法 , 导入定名空间 :
  1. // 使用自定义的命名空间
  2. // 注意 : 使用命名空间需要在 定义命名空间之后
  3. using namespace MyNamespace;
复制代码
注意 : 使用 定名空间 必要在 定义定名空间之后 , 否则会报错 ;

3、使用默认的定名空间


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

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



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


完整代码示例 :
  1. // 包含 C++ 头文件
  2. #include "iostream"
  3. // 使用 std 标准命名空间
  4. //                该命名空间中 , 定义了很多标准定义
  5. using namespace std;
  6. // 自定义命名空间
  7. namespace MyNamespace {
  8.         // 声明标识符  
  9.         int myVariable = 10;
  10.         void myFunction() {
  11.                 // 函数体  
  12.                 cout << "MyNamespace myFunction" << endl;
  13.         }
  14. }
  15. // 使用自定义的命名空间
  16. // 注意 : 使用命名空间需要在 定义命名空间之后
  17. using namespace MyNamespace;
  18. int main() {        cout << "定名空间中的变量 : " << myVariable << endl;        myFunction(); // 调用定名空间中的函数                 // 控制台暂停 , 按恣意键继续向后执行        system("pause");}
复制代码
执行结果 :
  1. 命名空间中的变量 : 10
  2. MyNamespace myFunction
  3. Press any key to continue . . .
复制代码






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

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


在 yvals_core.h 头文件中 , 定义了 std 定名空间相关的宏定义 , 如 : _STD_BEGIN  , _STD_END  , _STD  等 ;
  1. // NAMESPACE
  2. #define _STD_BEGIN namespace std {
  3. #define _STD_END }
  4. #define _STD ::std::
复制代码

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


在 C++ 代码中 , 经常见到 下面两行代码 在一起使用 ,
使用 C++ 的 iostream 标准流时 , 必要使用 #include "iostream" 代码先导入该标准库 ;
由于 iostream 头文件中没有定义 全局定名空间 , 如果要使用 cin 大概 cout , 必须加上 std:: 前缀 , 如 : std::cin 和 std::cout ;
  1. // 包含 C++ 头文件
  2. #include "iostream"
  3. // 使用 std 标准命名空间
  4. //                该命名空间中 , 定义了很多标准定义
  5. using namespace std;
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

民工心事

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表