理解 C++ 名称空间(namespace)

理解 C++名称空间(namespace)


在看《C++ Primer Plus》第 9 章名称空间时,一些个人的理解,如有错误欢迎指出。

  • 声明区域:传统的C++中,声明区域有如下几种:在函数外面声明的变量,其声明区域为所在文件;在函数内声明的变量,其声明区域为其所在的代码块

  • 名称空间(namespace):个人理解是一种特殊的声明区域,他是一种人为划定出来的名称空间,使用起来更加灵活,它看起来像下面这样。

    namespace Jack {
        double fetch;
        int sum(int a, int b) {
            return a + b;
        };
    }
    

    有三种方式使用它:

    方式1 使用作用域解析运算符::

    如下面这个例子:

    namespace Jack {
        double fetch;
    }
    
    int main() {
        Jack::fetch = 3;
        cout << Jack::fetch << endl;
        return 0;
    }
    

    输出:

    3
    

    方式2 using <名称空间的名字>::<名称>

    直接把名称空间里的声明,添加过来。

    namespace Jack {
        double fetch;
    }
    int main() {
        using Jack::fetch; 
        int fetch = 0;  // 这条语句会报错!因为fetch已经定义了
    }
    

    上面这个例子有点类似下面这种情况,即重复的声明了fetch

    int main() {
        double fetch = 1;  
        int fetch = 0;  // 这条语句会报错!因为fetch已经定义了
    }
    

    但绝对不是等同的,即using Jack::fetch并不是定义了一个局部变量,而只是使用了Jack中的fetch。

    namespace Jack {
        int fetch;
    }
    void change_fetch() {
        ++Jack::fetch; 
    }
    
    int main() {
        using Jack::fetch;
        fetch = 1;
        cout << fetch << endl;
        change_fetch();
        cout << fetch << endl;
        return 0;
    }
    

    输出:

    1
    2
    

    再比如下面这个,函数声明的例子。

    namespace Jack {
        int sum(int a, int b) {
            return a + b;
        };
    }
    
    int main() {
        using Jack::sum;
        cout << sum(1,2) << endl;
        cout << Jack::sum(1,2) << endl;  // 这种用法总是对的,不管前面用了using namespace还是using Jack::sum
        return 0;
    }
    

    下面这段代码也是对的,注意看和上面例子之间的区别和联系

    int main() {
        int sum(int a, int b);
        cout << sum(1,2) << endl;
        return 0;
    }
    
    int sum(int a, int b) {
        return a + b;
    };
    

    对比上面两个例子,可以看出, using Jack::sum,把函数声明添加了进来,虽然说namespace里有写函数的具体代码,但显然using Jack::sum只添加了声明,而没添加代码。下面这个代码是错的,因为函数里不能再定义一个函数:

    int main() {
        int sum(int a, int b) {  // 函数里不能再定义函数
        	return a + b;
    	};
        cout << sum(1,2) << endl;
        return 0;
    }
    

    方式3 using namespace <名称空间的名字>

    只考虑namespace Jack在函数外面的情况。那么using namespace Jack可以让名称空间Jack里的名称,可以被「看到」并使用,不需要再使用::了。

    但具体取决于这条语句在函数外还是函数里。

    如果using namespace Jack在函数外面,那么整个文件都可以看到并直接使用 Jack里的名称了(这就和在函数外声明的全局变量或者函数很类似了

    如果using namespace Jack在函数里,那就是该函数内部里可以「看到」并使用Jack里的声明,这里说是代码块,但整个文件也可以看作代码块嘛,比如在main中使用Jack里的声明:

    namespace Jack {
        double fetch;
    }
    
    int main() {
        using namespace Jack;
        fetch = 2; // Jack名称空间里的fetch
        cout << fetch << endl;
        int fetch = 3;  // 这条语句不会报错哦,局部的int fetch会隐藏掉Jack的double pail,注意是隐藏,不是覆盖
        cout << fetch << endl;  // 打印出局部的int fetch的值
        cout << Jack::fetch << endl;  // Jack::fetch依旧存在,输出可以发现仍然是2!
        return 0;
    }
    

    输出:

    2
    3
    2
    

    上面这个例子,和下面这个很相似,

    double fetch;
    
    int main() {
        fetch = 2;
        cout << fetch << endl;
        int fetch = 3;  // 这条语句不会报错哦,局部的int fetch会隐藏掉全局的double fetch,注意是隐藏,不是覆盖
        cout << fetch << endl;  // 打印出局部的int fetch的值
        cout << ::fetch << endl;  // 全局的fetch依旧存在,输出可以发现仍然是2!
        return 0;
    }
    

    输出:

    2
    3
    2
    

    上面的例子中,在main函数外面,定义了一个全局变量fetch,然后同样在main内部又定义了一个int类型的fetch,这样全局变量就被「隐藏」,通过作用域解析运算符::,仍然可以访问到全局变量,可以发现它依旧在那里。

    在函数外面的namespace Jack,此时就好像普通全局变量和其他函数声明一样,只不过它们被放到namespace中了。

    再看一个例子:

    char fetch;
    namespace Jack {
        int fetch;
    }
    
    int main() {
        using namespace Jack;  // 使用了using namespace Jack,再想访问fetch就必须得用::fetch了,因为直接用fetch被认为是Jack里的fetch
        Jack::fetch = 1;  // Jack的fetch
        ::fetch = 'a';  // 如果没有using namespace Jack, 这里就不用::也可以了
        double fetch = 2.1;  // 局部的double fetch
        fetch = 0.1;  // 局部的double fetch
        cout << Jack::fetch << endl;  // Jack里的fetch
        cout << ::fetch << endl;  // 全局的char fetch
        cout << fetch << endl;
        return 0;
    }
    

    输出:

    1
    a
    0.1
    

    这个例子里有三个fetch,全局的char fetch,namespace Jack的int fetch,还有main中定义的局部变量double fetch,在这种情况下,fetch仅指代局部的double fetch::fetch指代全局的char fetchJack::fetch指代namespace Jack的int fetch

    而在下面这个例子中,只能使用::了。fetch将不知道指代谁,从而报错:

    char fetch;
    namespace Jack {
        int fetch;
    }
    
    int main() {
        using namespace Jack;  // 使用了using namespace Jack,再想访问fetch就必须得用::fetch了,因为直接用fetch被认为是Jack里的fetch
        Jack::fetch = 1;  // 正确,Jack的fetch
        ::fetch = 'a';  // 正确,如果没有using namespace Jack, 这里就不用::也可以了
        fetch = 0.1;  // 错误!不清楚是哪个fetch,因为全局的char fetch和Jack的fetch冲突了
        return 0;
    }
    

    只有去掉char fetch的声明,或者去掉using namespace Jack,直接使用fetch,才会有明确的指向。

猜你喜欢

转载自blog.csdn.net/weixin_44286126/article/details/129773976
今日推荐