• C++ 命名空间-----namespace(超详细解析,小白必看系列)


    目录

    一、前言

     🍎什么是C++

    二、关键字 

    三、命名空间(重点)

    🍐C语言--命名冲突 

    🍉C++--命名空间的定义

    🍓C++--命名空间的使用

     四、C++输入&输出

    五、共勉 


    一、前言

            既博主学过C语言后又一新的语言,C++。总算既C语言 -- > 数据结构基础后又一新专栏专属于C plus plus。相信博主会通过博客的方式将C++的各个知识点细化的讲解出来,一起见证~的成长

     🍎什么是C++

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

    1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。


    正文开始

    二、关键字 

    C++总计63个关键字,C语言32个关键字,先看个总览,具体每一个对应的是什么在后面的博文中会进行剖析

    三、命名空间(重点)

    • 可能诸位在看别人写的C++代码中,在一开始会包这个头文件:
    #include

            这个头文件等价于我们在C语言学习到的 #include,它是用来跟我们的控制台输入和输出的,这里简要提下,后续详谈。

    •  除了上面这个头文件,还有这样一行代码:
    using namespace std;

           namespace就是我们要接触C++的第一个关键字,它就是命名空间

    • 作用如下:

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

    🍐C语言--命名冲突 

             在正式引入namespace前,再来回顾下C语言的命名冲突问题:

    1. #include
    2. #include
    3. // 命名冲突
    4. // rand 是库中的一个函数
    5. // 自己又定义了一个与其名字相同的一个变量
    6. int rand = 0;
    7. int main()
    8. {
    9. printf("%d", rand);
    10. return 0;
    11. }

            如上的代码中,头文件我们只用了intclude,暂无其它。我们定义了全局变量rand,并且代码可以正常编译没有任何错误。但是要知道C语言存在一个库函数正是rand,但是要包上头文件#include,包上了这个头文件,再运行试试:

            这里很明显发生了命名冲突了,我们定义的全局变量rand和库里的rand函数冲突

    想要解决此问题也非常简单,可能有人会说我修改变量名就可以了,确实可以,但并不是长久之计,如若我在不知情的状态下使用该变量超过100次,难道你要一个一个修改吗,这就充分体现了C语言的命名冲突

    • 在C++中,引入的命名空间namespace就很好解决了C语言的命名冲突问题。

    🍉C++--命名空间的定义

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

    如下:

            同一个作用域不能出现两个相同变量,此时的 rand 被关在 n1 的命名空间域里了,跟其它东西进行了隔离。所以在 stdlib.h 头文件展开时并不会发生命名冲突。此时 rand 的打印均是库函数里rand的地址,rand就是一个函数指针,打印的就是地址
     

             此段代码更充分的体现了加上命名空间,不仅可以避免命名冲突,而且还告诉我们,此时再访问变量m、c、f,均是在全局域里访问的,而xzy这个命名空间域里的变量与全局域建立了一道围墙,互不干扰。不过这里c和m依旧是全局变量,命名空间不影响生命周期。


    命名空间有三大特性:

    • 1、命名空间可以定义变量,函数,类型
    1. //1. 普通的命名空间
    2. namespace N1 // N1为命名空间的名称
    3. {
    4. // 命名空间中的内容,既可以定义变量,也可以定义函数,也可以定义类型
    5. int a; //变量
    6. int Add(int left, int right) //函数
    7. {
    8. return left + right;
    9. }
    10. struct ListNode //类型
    11. {
    12. int val;
    13. struct ListNode* next;
    14. }
    15. }
    • 2、命名空间可以嵌套
    1. //2. 命名空间可以嵌套
    2. namespace N2
    3. {
    4. int a;
    5. int b;
    6. int Add(int left, int right)
    7. {
    8. return left + right;
    9. }
    10. namespace N3
    11. {
    12. int c;
    13. int d;
    14. int Sub(int left, int right)
    15. {
    16. return left - right;
    17. }
    18. }
    19. }
    • 3、同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中
    1. //3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
    2. namespace N1
    3. {
    4. int Mul(int left, int right)
    5. {
    6. return left * right;
    7. }
    8. }

     🍓C++--命名空间的使用

      我们都清楚在C语言中,存在局部优先规则,如下:

    1. int a = 0; //全局域
    2. int main()
    3. {
    4. int a = 1; //局部域
    5. printf("%d\n", a); // 1 局部优先
    6. return 0;
    7. }

    我们都清楚这里的结果是1,但是如若我非要打印全局域里的a呢?

    这里引出域作用限定符 ( :: ),效果如下:

    加上了( :: ) ,此时访问的a,就是全局域,这里是全局域的原因是“ ::”的前面是空白,如若是空白,那么访问的就是全局域,这么看的话,我在“ ::”前面换成命名空间域,不就可以访问命名空间域里的内容了吗。其实“ ::”就是命名空间使用的一种方式。

    比如我们定义了如下的命名空间:

    1. namespace n1
    2. {
    3. int f = 0;
    4. int rand = 0;
    5. }

     现在该如何访问命名空间域里的内容呢?其实有3种方法:

    1. 加命名空间名称及作用域限定符“ ::
    2. 使用using namespace 命名空间名称全部展开
    3. 使用using将命名空间中成员部分展开
    • 1、加命名空间及作用域限定符“ ::
    1. int main()
    2. {
    3. printf("%d\n", n1::f); //0
    4. printf("%d\n", n1::rand);//0
    5. return 0;
    6. }

    为了防止定义相同的变量或类型,我们可以定义多个命名空间来避免

    1. namespace ret
    2. {
    3. struct ListNode
    4. {
    5. int val;
    6. struct ListNode* next;
    7. };
    8. }
    9. namespace tmp
    10. {
    11. struct ListNode
    12. {
    13. int val;
    14. struct ListNode* next;
    15. };
    16. struct QueueNode
    17. {
    18. int val;
    19. struct QueueNode* next;
    20. };
    21. }

    当我们要使用它们时,如下:

    1. int main()
    2. {
    3. struct ret::ListNode* n1 = NULL;
    4. struct tmp::ListNode* n2 = NULL;
    5. return 0;
    6. }

    针对命名空间的嵌套,如下:

    可以这样进行访问:

    1. int main()
    2. {
    3. struct tx::List::Node* n1; //访问List.h文件中的Node
    4. struct tx::Queue::Node* n2;//访问Queue.h文件中的Node
    5. }

    但是上述访问的方式有点过于麻烦,可不可以省略些重复的呢?比如不写tx::,这里就引出命名空间访问的第二种方法:

    • 2、使用using namespace 命名空间名称全部展开
    using namespace tx;
    

    这句话的意思是把 tx 这个命名空间定义的东西放出来,所以我们就可这样访问:

    1. int main()
    2. {
    3. struct List::Node* n1; //访问List.h文件中的Node
    4. struct Queue::Node* n2;//访问Queue.h文件中的Node
    5. }

    当然,我还可以再拆一层,如下:

    1. using namespace tx;
    2. using namespace List;
    3. int main()
    4. {
    5. struct Node* n1; //访问List.h文件中的Node
    6. struct Queue::Node* n2;//访问Queue.h文件中的Node
    7. }

    展开时要注意tx和List的顺序不能颠倒

    这种访问方式是可以达到简化效果,但是也会存在一定风险:命名空间全部释放又重新回到命名冲突。


    所以针对某些特定会出现命名冲突问题的,需要单独讨论:
     

    (重点,后期常用)由此我们得知:全部展开并不好,我们需要按需索取,用什么展开什么,由此引出第三种使用方法
     

    • 3、使用using将命名空间中成员展开

     针对上述代码,我们只放f出来

    1. namespace n1
    2. {
    3. int f = 0;
    4. int rand = 0;
    5. }
    6. using n1::f;
    7. int main()
    8. {
    9. f += 2;
    10. printf("%d\n", f);
    11. n1::rand += 2;
    12. printf("%d\n", n1::rand);
    13. }
    • 学到这,我们来看下C++的标准库命名空间:
    1. #include<iostream>
    2. using namespace std; //std 是封C++库的命名空间
    3. int main()
    4. {
    5. cout << "hello world" << endl; // hello world
    6. return 0;
    7. }

    如若省去了这行代码:

    using namespace std; 

    想要输出hello world就要这样做:

    1. #include<iostream>
    2. int main()
    3. {
    4. std::cout << "hello world" << std::endl;
    5. return 0;
    6. }

    当然也可以这样:

    1. #include<iostream>
    2. using std::cout;
    3. int main()
    4. {
    5. cout << "hello world" << std::endl;
    6. return 0;
    7. }

    这就充分运用到了命名空间,至于为什么会这样相信不需要我解释大家就能悟出来哈。
     

     四、C++输入&输出

    C语言中,我们都清楚输入用scanf,输出用printf,可是在C++中,我们同样可以用C语言的,不过C++也独有一套输入cin输出cout。

    • 说明:

    使用cout标准输出(控制台)和cin标准输入(键盘)时必须包含< iostream >头文件以及std标准命名空间。
    注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持格式,后续编译器已不支持,因此推荐使用+std的方式。

    1. // >> 流提取运算符
    2. cin >> a;
    3. // << 流插入运算符
    4. cout << a;

    C++里的输入输出流可以自动识别类型,不需要像C语言一样不需增加数据格式控制,比如:整形--%d,字符--%c

    注意:endl是换行符,等价于C语言的\n '。

    最后,我们依旧是以经典的hello world结束C++的输入输出

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. cout << "hello world" << endl;
    6. }

    五、共勉 

    以下就是我对C++---namespace 命名空间的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++-------缺省参数的理解,请持续关注我哦!!!!!  

  • 相关阅读:
    成都精灵云复试完结篇
    linux中的lo介绍及作用(回环接口 回环IP)
    机器学习实战应用案例100篇(十九)-鲸鱼算法从原理到实战应用
    顺序表第一部分(介绍篇),三部曲后面分别是实现和介绍
    【上海大学计算机组成原理实验报告】四、指令系统实验
    regexp_extract用法
    如何为测试自动化准备您的敏捷 QA 团队
    GMT中标注特殊字符:平方,%,±号,希腊字母
    【接口性能优化】一、SQL优化篇
    SpringBoot war包部署到tomcat上无法访问的异常处理
  • 原文地址:https://blog.csdn.net/weixin_45031801/article/details/133777138