• 【C++】命名空间


    在C语言中有下面一段代码:

    #include 
    int main() {
        int scanf = 0;
        scanf("%d", &scanf);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这段代码会报错。

    首先 scanf 是一个函数名,不是C语言的关键字,所以定义一个名为 scanf 的局部变量是没有任何问题的。

    但是,当我想调用 scanf 函数去给定义的临时变量 scanf 赋值的时候却出现了问题。

    我们以为是函数名的 scanf 也被编译器当成了临时变量:

    image-20220804201910112

    亦或者是下面一段代码:

    #include 
    int scanf = 0;
    int main() {
        printf("%d", scanf);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这段代码报错说 scanf 重定义。这段代码与上面不同的是 scanf 定义成了全局变量,而在头文件 stdio.hscanf 也被定义了一次。在预处理阶段会进行头文件的展开,这样就导致了报错所说的那个问题。

    image-20220804202153004

    上面两个案例就引出了一个问题——命名污染

    C++ 为了解决这个问题,引入了命名空间


    命名空间的定义

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

    比如下面的一些使用方法:

    //1. 普通的命名空间
    namespace N1 // N1为命名空间的名称
    {
    	// 命名空间中的内容,既可以定义变量,也可以定义函数
        int a;
        int Add(int left, int right)
        {
        	return left + right;
        }
    }
    
    //2. 命名空间可以嵌套
    namespace N2 {
        int a;
        int b;
        int Add(int left, int right) {
        	return left + right;
        }
        namespace N3 {
            int c;
            int d;
            int Sub(int left, int right){
                return left - right;
            }
        }
    }
    
    //3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
    namespace N1 {
        int Mul(int left, int right) {
            return left * right;
        }
    }
    
    • 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

    解释一下第三段代码。

    它和第一段代码的命名空间都叫 N1 ,命名空间相同的命名符号会在链接过程中合并,所以 aAddMul 是同属一个命名空间的。

    一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中,当出了这个命名空间的作用域,里面定义的各种变量名也就跳出了生命周期。


    命名空间的使用

    我们在初次接触C++的代码时可能会看到下面的代码:

    //1
    using namespace std;
    int main() {
        cout << "hello world" << endl;
        return 0;
    }
    
    //2
    int main() {
        std::cout << "hello world" << std::endl;
        return 0;
    }
    
    //3
    using std::cout;
    int main() {
        cout << "hello world" << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    其实上面三段代码就反映了命名空间的三种主要使用方法。

    下面解释一下。

    首先说明一点,cout 是*C++*的输出函数,它是定义在命名空间 std 中的,std 中还定义了一个输入函数 cin ,下面讲解会拿它来举例。

    1 处是将命名空间 std 全部展开,这也就意味着 std 中的任何一个变量名都不能被再次重定义,假如我添加一行 int cin = 0;编译器就会报错。这样的好处是对命名空间中的变量名可以直接使用,而不用加限定符。但缺点也同样明显,就是在协同工作中可能会引发命名冲突的问题

    2 处是使用了命名空间名称+作用域限定符的方式。这样的好处是避免了命名冲突的问题,即使我又定义了一个 int cout = 0; 编译器也不会报错。缺点同样明显,就是使用起来太麻烦了。

    3 处是工程中最标准也是最推荐的使用方式,对命名空间中的哪个成员用的多就单独把它引用进来,这样只需要避免重定义引进来的这个成员就可以规避命名冲突,这样最大程度地避免了命名冲突的问题,写起来代码也不会太麻烦。

  • 相关阅读:
    基于 Spring Boot 博客系统开发(一)
    nagios
    【Linux】vim及gcc/g++的使用
    centos7 离线升级/在线升级操作系统内核
    Mysql时间操作
    算法:合并两个有序数组---双指针[1]
    Mac图像编辑器Pixelmator Pro
    前端框架的发展历程
    FlinkSQL ChangeLog
    强化学习简介
  • 原文地址:https://blog.csdn.net/Ye_Ming_OUC/article/details/126202966