使用命名空间里的名字,一共三种方式:① 写全名(std::cout,最清楚、工程首选);② using 声明(using std::cout;,只放行一个名字,折中推荐);③ using namespace 指令(using namespace std;,整个放行,省字但风险大)。此外还有第四种实用工具:命名空间别名(namespace fs = std::filesystem;)——专治"名字太长"。
10.6 讲了"命名空间是什么、为什么需要",本节把"怎么用"说全。这里是 6.4 作用域思路的又一次应用:using 声明/指令都只在"它所在的作用域内"有效——写在函数里,就只影响那个函数。这个规律很重要,它让你可以"在局部放心地简化"。
一、三种使用方式(含优缺点)
方式 ① 写全名——最清楚
std::cout << "hello" << std::endl;
math::square(4);
| 优点 | 缺点 |
|---|---|
| 一眼看出"这个名从哪来";不会撞名;头文件里也安全 | 打得长,代码稍显啰嗦 |
工程上这是默认推荐的做法。 很多公司代码规范明确要求"不许写 using namespace"。
方式 ② using 声明——只放行一个名字
using std::cout; // 只把 cout 放出来
using std::endl;
cout << "hello" << endl; // ✅ 能用
// string s; // ❌ 不行:string 没被放行
std::string s2; // 还得写全名
要点:
| 点 | 说明 |
|---|---|
| 一次只放行一个名字 | 想用几个就写几行 |
| 它的作用 | 相当于"在本作用域里,给这个名字装一个直通入口" |
| 推荐场景 | 函数内部的局部简化(风险最小) |
这是三种里最平衡的一种:省了字,风险又可控。
方式 ③ using namespace 指令——整个放行
using namespace std; // std 里所有名字都放出来
cout << "hello" << endl;
string s;
| 优点 | 缺点 |
|---|---|
| 最省字 | 放出成千上万个名字,撞名风险最大;放头文件里就是灾难 |
用途:练习、小程序、教程示例。别用在头文件、别用在正经项目里(10.6 讲的)。
二、三者对比表
| 写全名 | using std::cout; |
using namespace std; |
|
|---|---|---|---|
| 写多长 | 长 | 中 | 最短 |
| 放行范围 | 无(不改动任何东西) | 一个名字 | 整个命名空间 |
| 撞名风险 | 无 | 小(只那一两个名字) | 大 |
| 头文件里能用吗 | ✅ 能 | ⚠️ 尽量别(会影响包含者) | ❌ 绝对别 |
| 推荐程度 | 工程首选 | 局部简化首选 | 只在练习里用 |
三、作用域决定 using 的范围
这是本篇最实用的一条规律:
using声明和指令,只在"它所在的那个作用域"内有效。(6.4 的知识)
#include <iostream>
void f1() {
using namespace std; // 只在 f1 里有效
cout << "f1 里能直接用" << endl;
}
void f2() {
// cout << "x"; // ❌ f2 里不行:f1 里的 using 管不到这儿
std::cout << "f2 里得写全名" << std::endl;
}
int main() {
f1();
f2();
{ // 一个块
using std::cout; // 只在这个块里有效
cout << "块里也能用" << endl;
}
return 0;
}
这条规律的两个好处:
| 好处 | 说明 |
|---|---|
| 可以"局部放开" | 在个别函数里图省事,不影响别的函数 |
| 可以"用完就收" | 出了那个块,using 就失效了——风险被关在小盒子里 |
好习惯:实在懒得写全名,就把
using namespace std;写进函数体里,别写在文件开头。 这样它的影响范围从"整个文件"缩小到"一个函数"——同样是省事,风险小一个数量级。
四、第四种工具:命名空间别名
问题:有些命名空间名字又长又有层次:
std::filesystem::path p = "C:/data";
my_company::network::protocol::HttpClient client;
解法:起个外号——
namespace fs = std::filesystem; // fs 就是它的别名
fs::path p = "C:/data"; // 清爽多了
再举一例:
namespace net = my_company::network::protocol;
net::HttpClient client; // 一下子短了很多
三条要点:
| 点 | 说明 |
|---|---|
| 写法 | namespace 别名 = 原名;(别名在前,和 typedef 的 8.2 一个风格) |
| 作用域 | 和 using 一样,只在本作用域内有效 |
| 用途 | 长名字的命名空间(尤其嵌套的,10.6.4 会遇到) |
它和
using的区别:using是"把名字放出来",别名是"换个短称呼"。别名从不清空"谁属于谁"这层信息(还得写fs::),所以更安全。长名字场景首选它。
五、动手 Demo:三种方式 + 别名的完整对照
#include <iostream>
namespace company {
namespace hr { // 嵌套命名空间(10.6.4)
void hire() { std::cout << "HR:发出录用通知" << std::endl; }
void fire() { std::cout << "HR:办离职手续" << std::endl; }
}
void report() { std::cout << "公司:出季度报表" << std::endl; }
}
int main() {
// ① 写全名(工程首选)
company::report();
company::hr::hire();
// ④ 别名:给长名字起外号
namespace hr = company::hr; // 在本作用域内
hr::fire();
hr::hire(); // 用别名调,一样能用
// ② using 声明:只放行一个
{
using company::report;
report(); // 只在这个块里能这么写
}
// report(); // ❌ 出了块就不行了
// ③ using namespace:整个放行(写在局部,风险可控)
{
using namespace company;
report(); // 能用了
std::cout << "(这一段里 company 的名字都放行了)" << std::endl;
}
std::cout << "程序结束" << std::endl;
return 0;
}
看到什么算成功:
公司:出季度报表
HR:发出录用通知
HR:办离职手续
HR:发出录用通知
公司:出季度报表
公司:出季度报表
(这一段里 company 的名字都放行了)
程序结束
读结果三句话:
- 别名
hr能像真名一样用(hr::fire()),而且能反复用——它是"换称呼",不是"放行名字"。 using company::report;放进了块里——出了块就失效(所以后面的using namespace那段还要再来一次)。- 全篇用
std::cout而没写一句using namespace std;——照样跑得很顺。
30 秒实验:把 namespace hr = company::hr; 挪到 main 外面(文件级),然后在另一个函数里用 hr::fire()。你会发现也能用——因为别名的有效范围也遵守作用域规则:写在文件级就是全文件可用(这就是"全局别名")。反过来,把它写在某个块里,就只在那个块里有效。
六、常见误区
- "三种方式效果一样,随便挑"——效果确实一样(功能上),但风险差别很大。方式①最安全、方式③最省字也最危险。 选哪个是"规范"问题,不是"对不对"问题。
- "
using namespace std;写在文件开头是标准做法"——恰恰相反。它是教程为了排版简洁的写法,工程规范基本都禁止(尤其头文件里)。从今天起,试着把它从"文件开头"挪到"函数体里",或者干脆用全名。 - "
using声明和using指令是一回事"——不是。using std::cout;(声明)只放行一个名字;using namespace std;(指令)放行整个命名空间。前者风险小得多。 - "命名空间别名会"改变"名字的归属"——不会。
fs::path和std::filesystem::path是同一个东西,别名只是让你少打字。(这点和typedef8.2 很像:只是换个名字。) - "
using可以写在命名空间里"——可以,但要注意:using指令写在命名空间内部,会让那个命名空间"出口"变宽(别人包含它时更容易撞名)。这也是"头文件里别写using namespace"这条规矩的一部分。
自测三问(点开对答案)
1. 三种使用方式各是什么?工程里首选哪一种?——① **写全名**(`std::cout`);② **`using` 声明**(`using std::cout;`,只放行一个名字);③ **`using namespace`**(整段放行)。**工程首选 ①**(最清楚、绝不撞名);**局部简化可用 ②**。 2. `using std::cout;` 和 `using namespace std;` 有什么区别?——**前者只放行 `cout` 这一个名字**(其他还得写 `std::`);**后者把 `std` 里所有名字都放出来**。**前者风险小得多。** 3. 命名空间别名怎么写?它和 `using` 有什么区别?——写法:**`namespace 别名 = 原名;`**(别名在前)。区别:**别名是"换个短称呼"**(还得写 `别名::名字`,**保留了归属信息**);**`using` 是"把名字放出来"**(可以直接裸写名字)。**长名字场景首选别名。**- ☐ 10.6.2 定义命名空间(下一节)