JMing's Blog

C++中的命名空间

字数统计: 1.1k阅读时长: 4 min
2024/05/20

什么是命名空间

命名空间是用于表示一组标识符的可见范围,用于解决标识符重定义的问题。

命名空间的使用

例子引入

我们正在进行多人开发或大项目开发时,可能会出现标识符重定义的问题,也就是变量名、函数名、类名可能会存在重复的问题。

1
2
3
4
5
6
7
8
9
10
11
/* file_a.cpp */
#include <iostream>

void SayHello() {
std::cout << "Hello. I am JM" << std::endl;
}

int main() {
SayHello();
return 0;
}
1
2
3
4
5
6
/* file_b.cpp */
#include <iostream>

void SayHello() {
std::cout << "Hello. I am AA" << std::endl;
}

可以看到 file_a.cppfile_b.cpp 中同时出现了同名函数且不构成函数重载。

如果我们此时进行编译的话会不通过,会出现链接错误并提示你: duplicate symbols

虽然这个例子举得可能不恰当,似乎并不会有人这样做,但是相信我,你一定会出现类似问题的,这也是命名空间存在的意义。

命名空间的语法

  • 声明一个命名空间

namespace 命名空间名 { /\* some identifiers \*/ }

1
2
3
4
5
namespace ns {
int a = 10;
class ClassA {}
void A() {}
}
  • 访问命名空间中的内容

命名空间名::标识符

1
2
3
4
5
#include <iostream>
int main() {
std::cout << ns::a << std::endl; // 10
return 0;
}

使用 using 使用命名空间

我们可以使用 using 关键字使用命名空间,使得命名空间中的内容在此作用域内可见,从而不需要通过作用域运算符访问命名空间中的内容。

  • 使用整个命名空间

using namespace 命名空间名;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

namespace aaa {
int a = 10;
int b = 20;
}

/* 使用了 std 和 aaa 两个命名空间 */
using namespace std;
using namespace aaa;

int main() {
/* 下面两条语句的效果相同 */
std::cout << aaa::a << aaa::b << std::endl;
cout << a << b << endl;
return 0;
}
  • 使用命名空间中的部分内容

using 命名空间名::标识符;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

namespace aaa {
int a = 10;
int b = 20;
}

/* 使用了 std 中的 cout 与 endl */
using std::cout, std::endl;

/* 使用了 aaa 中的 a */
using aaa:a;

int main() {
std::cout << aaa::a << aaa::b << std::endl;

/* 并没有使用 aaa 中的 b,所以还需要使用作用域运算符访问 */
cout << a << aaa::b << endl;
return 0;
}

在定义和使用命名空间时的注意点

  • 命名空间的大括号后面不需要分号结束。

  • 命名空间内的缩进可以根据个人喜好或公司代码规范来调整。

  • 可以在一个文件内出现多个命名空间,也可以在多个文件内出现同一个名字的命名空间,但同名命名空间内绝对不能出现重名的标识符。

    • 一个文件出现多个命名空间 ✅
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>
    namespace aaa {
    int a = 10;
    }

    namespace bbb {
    int a = 20;
    }
    int main() {
    std::cout << aaa:a << endl; // 10
    std::cout << bbb:a << endl; // 20
    }
    • 多个文件中出现同一个名字的命名空间 ✅
    1
    2
    3
    4
    /* file_a.cpp */
    namespace aaa {
    int a = 10;
    }
    1
    2
    3
    4
    /* file_b.cpp */
    namespace aaa {
    int b = 20;
    }

    这样做并不好,因为这样虽然编译能通过,但是在 file_a.cpp 中并不能够访问到 file_b.cpp 中的那部分。

    所以正确的做法是将它们放在不同的头文件中来方便我们引入,如果你需要在命名空间中存放的内容并不多,且内容同属一个模块,那么直接放在一个文件中即可。

    • 多个文件中出现同一个名字的命名空间,并出现了重名的标识符 ❌
    1
    2
    3
    4
    5
    /* file_a.cpp */
    /* 错误示范 */
    namespace aaa {
    int a = 10;
    }
    1
    2
    3
    4
    5
    /* file_b.cpp */
    /* 错误示范 */
    namespace aaa {
    int a = 20;
    }

    这样做就等同于在一个作用域内声明/定义了同名标识符

    1
    2
    3
    4
    5
    /* 错误示范 */
    namespace aaa {
    int a = 10;
    int a = 20;
    }
  • using 命名空间时,也请保证在一个作用域内不会出现可见的多个同名标识符,否则编译不通过,出现链接错误。

CATALOG
  1. 1. 什么是命名空间
  2. 2. 命名空间的使用
    1. 2.1. 例子引入
    2. 2.2. 命名空间的语法
    3. 2.3. 使用 using 使用命名空间
  3. 3. 在定义和使用命名空间时的注意点