• C++入门——域作用符,命名空间的讲解


    对于学完C语言的同学,马上就要迈入C++的门槛了,接下来就简单说说C++的入门基础知识吧。

    目录

    创建C++文件

     实现一个简单的C++程序——Hello World

    域作用限定符:: 

    2.命名空间 

    命名空间的嵌套

    命名空间使用的三种形式:

    1.命名空间名称+作业域限定符

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

    3.使用 using namespace 命名空间名称引入


    创建C++文件

            在之前,我们用的是.c文件,在以后的学习中,我们就要使用新格式的.cpp去编写程序了。

     实现一个简单的C++程序——Hello World

            对于Hello World我们是再熟悉不过了,好像又回到了那个刚开始学习C语言的时候,只不过这次的Hello World实现有些不同。

    1. #include
    2. using namespace std;
    3. #include
    4. int main() {
    5. //C语言的写法
    6. printf("Hello World\n");
    7. //C++写法
    8. cout << "Hello World" << endl;
    9. return 0;
    10. }

    域作用限定符:: 

            

    例:

    1. #include
    2. //全局变量
    3. int a = 0;
    4. int main() {
    5. //局部变量
    6. int a = 2;
    7. printf("%d\n", a);
    8. return 0;
    9. }

    通过上述代码我们发现:有两个相同名字的变量,一个是全局的,一个是函数局部的, 而printf打印出来的是:

            原因就在于:系统在编译过程中要符合局部优先性原则,先找局部变量的值,若有则输出,若局部中没有该变量就要到全局去找。

            那么就会出现一个问题,万一我只想要输出全局变量的值呢?那该怎么做?这就需要用到了域作用限定符了::

           域作用限定符,该限定符作用:可以避开局部的,直接访问全局的。用法:直接在变量前加上这个限定符即可。

    2.命名空间 

    例:

    1. #include
    2. int rand = 10;
    3. int main() {
    4. printf("%d\n", rand);
    5. return 0;
    6. }

            printf该语句会报错:rand 重定义;以前的定义是“函数”。无法运行。


     

            那么该如何解决?就是想要使用rand。这就要提到了命名空间,因为变量的命名大量存在,可能会导致很多冲突。使用命名空间的目的是避免命名冲突或者名字污染。

    命名空间的创建需要用到一个关键字:namespace  ,后面加命名空间的名字(随便什么都可以),然后加上花括号即可。

    例如:在下面的代码中新建一个命名空间bit:

    1. #include
    2. #include
    3. namespace bit {
    4. int rand = 1;
    5. int scanf = 2;
    6. }
    7. int main() {
    8. printf("%d\n", rand);
    9. //指定在bit限定域中找的话,可以找到
    10. printf("%d\n", bit::rand); //1
    11. printf("%d\n", bit::scanf); //2
    12. printf("%d\n",bit::x);
    13. return 0;
    14. }

            输出rand时会发现结果是一串数字,原因是main函数默认先找局部,局部找不到就找全局
    stdlib.h在预编译的时候就会被展开到全局中,所以main函数在全局找到了rand,只不过找到的是rand作为函数的地址!!! 

    而指定在bit限定域中找的话,可以找到rand的值。

    而对于bit空间里没有的变量,如上图 bit::x,编译器就会报错。

            总结:命名空间是有限制的,它虽然处在全局——静态区(所处位置很重要!!!),但是它是被上了锁的全局区域,或者说它被一堵墙围起来了,没有权限根本就进不去,需要指定域名和域作用限定符才能去打开那堵墙,才能访问到里面的东西。 

                

    命名空间的第二大优点:多个命名空间中同名的函数或者变量不会造成冲突。

    例:

    1. //命名空间1
    2. namespace bit {
    3. int Add(int a, int b) {
    4. return a + b;
    5. }
    6. struct Node {
    7. int val;
    8. struct Node* next;
    9. struct Node* prev;
    10. };
    11. }
    12. //命名空间2
    13. namespace byte {
    14. int Add(int a, int b) {
    15. return a * 10 + b * 10;
    16. }
    17. struct Node {
    18. int val;
    19. struct Node* next;
    20. };
    21. }
    22. int main() {
    23. printf("bit_Add:%d\n", bit::Add(1, 2));
    24. bit::Node n1;
    25. n1.val = 10;
    26. printf("bit_val:%d\n", n1.val);
    27. //————————————————————————
    28. printf("byte_Add:%d\n", byte::Add(1, 2));
    29. byte::Node n2;
    30. n2.val = 20;
    31. n2.next = NULL;
    32. printf("byte_val:%d\n", n2.val);
    33. return 0;
    34. }

            总结:不同名称的多个域中可以定义相同的变量或者函数名称,如上图:bit域中可以定义Add函数,byte域中也可以定义相同名字的Add函数;但多个头文件中名称相同的域中不可以定义两个相同名字的变量,函数。

    重点总结:1.域中的变量内容是存放在静态区的——全局变量,它们并不在栈上!!!

                      2.编译器的查找规则是先局部后全局的,局部没有找全局的,全局也没有的就报错!

                    


    命名空间的嵌套

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

    1. namespace bit {
    2. int a = 1;
    3. int b = 2;
    4. int Add(int x, int y) {
    5. return x + y;
    6. }
    7. namespace byte {
    8. int c = 20;
    9. int d = 30;
    10. int Sub(int x, int y) {
    11. return x - y;
    12. }
    13. }
    14. }
    15. int main() {
    16. printf("%d\n", bit::a);
    17. //嵌套——可以套很多层
    18. printf("%d\n", bit::byte::c);
    19. printf("%d\n", bit::byte::Sub(10, 20));
    20. return 0;
    21. }

             我们会发现:byte空间处在bit空间里面,要想访问到c,d等变量就需要先打开外层的锁,才能打开内层的锁去访问到——双重域定义。

    命名空间使用的三种形式:

    1.命名空间名称+作业域限定符

    1. namespace N {
    2. int a = 10;
    3. int b = 20;
    4. int Add(int x, int y) {
    5. return x + y;
    6. }
    7. }
    8. //方法1.:命名空间名称+作用域限定符
    9. int main() {
    10. printf("%d\n", N::Add(10, 20));
    11. return 0;
    12. }

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

    1. namespace N {
    2. int a = 10;
    3. int b = 20;
    4. int Add(int x, int y) {
    5. return x + y;
    6. }
    7. }
    8. //使用方法2.:
    9. using N::b;
    10. int main() {
    11. printf("%d\n", N::a); //10
    12. printf("%d\n", b); //20
    13. return 0;
    14. }

            这个变量b没有使用域作用限定符,却可以访问namespace N,就是因为提前声明了using N::b,让main有权限能够去访问N的成员b,也仅仅能访问到N的b成员罢了,N的其他成员还是得用::限定符修饰才可以访问。

    3.使用 using namespace 命名空间名称引入

    1. namespace N {
    2. int a = 10;
    3. int b = 20;
    4. int Add(int x, int y) {
    5. return x + y;
    6. }
    7. }
    8. using namespace N;
    9. int main() {
    10. printf("%d\n", a);
    11. printf("%d\n", b);
    12. int c = Add(10, 20);
    13. printf("%d\n", c);
    14. return 0;
    15. }

            直接引入空间名称,就不需要作用域限定符了,命名空间N的大门完全敞开,想访问哪个就访问哪个。

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

            例如一个文件有两个头文件.h,它们中拥有相同的bit命名空间,但里面的内容不同,那么在运行的时候,编译器会将将两个.h文件中的bit空间合并成一个命名空间去展开。


            之后C++官方又定义了一个标准的命名空间:std,里面存放了很多内容,比如我们常使用的cout和cin就是出自std命名空间中。一旦展开就可以调用库中所有内容,方便快捷,当不使用using namespce std时,直接使用cout编译器会识别不出,继而产生报错,必须加上std::才可以使用.

            在如下代码中,会发现,每加一句std::就很繁琐,所以在一般情况下可以在头文件处加上语句:using namespace std;

             当使用后,这堵墙也就消失了,那么就不能避免命名冲突了,若是使用与std中相同的命名会报错。此时可以进行部分展开。如下:

    1. #include
    2. using std::cout;
    3. using std::cin;
    4. using std::endl;
    5. int main() {
    6. //可以输出
    7. cout << "Hello World" << endl;
    8. int q = 100;
    9. int p = 200;
    10. cout << q<<" "<< p << endl; //100 200
    11. return 0;
    12. }

            部分展开——既不会发生命名冲突,还可以用上C++官方定义的std库。

  • 相关阅读:
    软件成分分析(SCA)完全指南
    如何进行MDM的产品测试
    LeetCode34 在排序数组中寻找元素的第一个和最后一个位置
    Selenium浏览器自动化测试框架简单介绍
    发布Android库至MavenCentral详解
    java经典笔试题大全(50道含答案)
    国内crm解决方案的主要提供商有哪些?对比7家
    【让你从0到1学会C语言】指针/数组传参以及static关键字
    b、B、KB、Kib、MB、MiB、GB、GiB、TB、TiB的区别
    02. 02-工厂模式
  • 原文地址:https://blog.csdn.net/weixin_69283129/article/details/127725354