【C++】命名空间namespace详解

一、命名空间的引入

C++中,名称(name)可以是符号常量、变量、宏、函数、结构体、枚举、类和对象等等。而在大型工程中,难免会有重名的现象,命名空间namespace,就是C++引入的一种解决名称冲突的机制

1.1 如何解决命名冲突

C语言中

C语言中是通过人为操作符号名称、限制符号的作用域和链接属性来完解决名称冲突的。比如:

  1. 同一个C文件中的全局变量/函数加一个统一的前缀
  2. 通过作用域的掩蔽规则来进行覆盖(在大文件中如果出错很难发现)
  3. C文件中的全局变量和函数都是extern链接属性,可以用static将无需跨文件访问的全局变量和函数限制在内链接属性中
Cpp中

为实现命名空间机制,C++中引入了namespace关键字,定义格式为

namespace NAME
{
    /*
        符号定义
    */
}

一个特定名称为NAME的命名空间的一对大括号内部定义的符号均被限制在该命名空间内,在命名空间内部各符号可以直接相互引用,而跨命名空间相互引用时必须同时指定被引用符号的命名空间名称。从某种意义上来说,命名空间就类似于一种前缀,本质上而言,就相当于控制了符号的作用域和链接属性。

二、namespace的使用

需要注意的是,命名空间不能定义在任何函数的内部,包括主函数,但是可以嵌套定义。

2.1 同一文件内常规使用namespace

namespace有三种使用方法:

  1. 使用时对符号附带命名空间的名称
  2. 使用前对该符号进行声明,后面直接使用该符号
  3. 使用前声明整个命名空间,后面对直接使用该命名空间中的任何符号
#include 

namespace NM1
{
    int a = 1;
    int b = 2;
}

void func1(void);

using namespace std;//声明std命名空间,后面可以使用该命名空间中的任何符号,如cout、endl...
using NM1::a;       //声明命名空间NM1中的a,后面可以直接对a进行使用

int main(void)
{
    cout << "the value of a is: " << a << endl;
    cout << "the value of b is: " ;
    cout << NM1::b;//使用变量时直接附带命名空间
    cout << endl;
    return 0;
}

2.2 命名空间内定义函数

我们可以在命名空间内直接定义函数,但是不能只声明不定义,否者链接时会出错

#include 

namespace NM1
{
    using namespace std;
    void func1(void)
    {
        cout << "Func1 in NM1" << endl;
    }

    void func2(void)
    {
        func1();
    }
}

using namespace NM1;

int main(void)
{
    func1();
    func2();
    return 0;
}

这是合法的使用
clipboard_20200214030329.png

如果我们只声明,而在默认命名空间(后文会阐述)中去定义,如下所示:

#include 

namespace NM1
{
    void func1(void);
}

using namespace NM1;

int main(void)
{
    func1();
    return 0;
}

void func1(void)
{
    std::cout << "Func1 in NM1" << std::endl;
}

则会出现链接错误,因为func1在定义和声明时不再同一个作用域
clipboard_20200214030932.png

2.3 嵌套使用命名空间

这个东西也很简单,如下测试代码

#include 

namespace NEST1
{
    using namespace std;
    void func1(void)
    {
        cout << "Func1 in NEST1" << endl;
    }
    namespace NEST2
    {
        void func2(void)
        {
            cout << "Func2 in NEST1::NEST2" << endl;
        }
    }
}

int main(void)
{
    NEST1::func1();
    NEST1::NEST2::func2();
    return 0;
}

clipboard_20200214032209.png

2.4 跨文件使用namespace

建立相应的测试文件

touch external_test.cpp external_test.h main.cpp CMakeLists.txt

对应的内容如下:

external_test.h

#ifndef CPP_EXTERNAL_TEST_H_
#define CPP_EXTERNAL_TEST_H_

namespace EX1
{
    void func(void);
}

#endif

external_test.cpp

#include "external_test.h"
#include 

namespace EX1
{   
    using namespace std;
    void func(void)
    {
        cout << "Func in EX1" << endl;
    }
}

main.cpp

#include "external_test.h"

using namespace EX1;

int main(void)
{
    func();
    return 0;
}

测试结果如下,EX1成功跨文件调用
【C++】命名空间namespace详解_第1张图片
在正规场合都是通过头文件的包含来进行namespace的跨文件调用,有时也可以通过对命名空间内的符号进行extern全局声明

建立相应的测试文件

touch external_test.cpp main.cpp CMakeLists.txt

相应内容如下:

extern_test.cpp中:

#include 

namespace EX1
{   
    using namespace std;
    void func(void)
    {
        cout << "Func in EX1" << endl;
    }
}

main.cpp

namespace EX1
{   
    extern void func(void);
}

using namespace EX1;

int main(void)
{
    func();
    return 0;
}

【C++】命名空间namespace详解_第2张图片

三、一些特殊的命名空间

3.1 std命名空间

标准C++库的所有的标识符(函数、类、模板等)是在一个名为std的命名空间中定义的,stdstandard(标准)的缩写,表示这是存放标准库的有关内容的命名空间。

3.2 默认命名空间

默认命名空间又叫全局命名空间,就是除了其他的命名空间之外的部分,比如说我们的主函数就是在默认命名空间中的,在其他命名空间引用默认命名空间中的符号的方法有两种:

  1. 直接使用
  2. 在符号前加::

3.3 匿名命名空间

匿名命名空间就是没有名字的命名空间,定义如下:

namespace
{
    /*
        符号
    */
}

匿名命名空间中的符号纯本空间内部使用,不能被外部引用,效果类似于全局变量和函数加static,但是比C中的static使用范围广

你可能感兴趣的:(C++,c++,namespace)