1. 命名空间:你的代码组织小能手
1.1 编译器的查找顺序
当我们编写代码时,编译器就像一位严格的图书管理员,它会按照特定的顺序来寻找我们需要的变量、函数或类型:
- (1)当前局部域:首先,它会在你当前作用域(即“自留地”)里搜索,这是最直接、最近的地方。
void myFunction() {
int x = 1; // 这里的x就是在当前局部域中定义的
}
- (2)全局域:如果在局部域找不到,编译器就会去全局域(想象成一个开放的“村子野地”)搜寻。
int globalX = 2; // 全局域中的变量globalX
void anotherFunction() {
// 在这里可以直接使用globalX,因为编译器会在全局域找到它
}
- (3)展开的命名空间:如果没有找到,如果你已经通过
using namespace
指令展开了某个命名空间,那么编译器会接着去这个“立了‘请自取’牌子的张大爷自留地”找。例如:
namespace zdy {
int y = 3;
}
// 展开命名空间zdy
using namespace zdy;
void someFunction() {
// 此时可以直接使用y,因为已展开的命名空间中有定义
std::cout << y;
}
请注意,默认情况下编译器不会主动去其他未展开的命名空间中寻找。
1.2 命名空间也能“套娃”
命名空间是可以嵌套的,就像俄罗斯套娃一样。如果在内部命名空间中出现了名称冲突,就需要明确指定访问哪个命名空间下的成员。
1.3 展开命名空间的艺术
全局域与展开的命名空间相遇时,全局域的成员具有优先权。你可以选择性地展开命名空间中的单个成员,但要避免随意展开整个命名空间以减少潜在的命名冲突风险。
namespace zdy {
int x;
}
int x = 4; // 全局域中的x
using zdy::x; // 只展开命名空间zdy中的x
void func() {
x = 5; // 此处修改的是全局域中的x,而不是zdy命名空间内的x
}
1.4 如何优雅地使用命名空间
- (1)指定访问:通过
namespace_name::member
的形式明确指定访问某个命名空间下的成员。 - (2)全展开:使用
using namespace namespace_name
来展开整个命名空间,但应谨慎使用。 - (3)指定展开某一个:如
using zdy::x
,仅展开命名空间内特定的成员。
1.5 命名空间总结
命名空间是一种特殊的域,除了局部域和全局域外,还有类域等,它们共同影响着成员的可见性。各个域中都可以定义同名的变量、函数或类型,通过命名空间机制可以有效管理这些重名资源。
2. C++ IO流:与程序进行交互的桥梁
#include <iostream>
std::cin >> var; // "c"表示console,从控制台读取输入赋值给var
std::cout << "Hello, World!"; // “流插入”,可以连续输出多种类型数据
// 控制输出数字精度可查阅文档或使用C风格的printf函数
double pi = 3.141592653589793238;
std::cout << std::fixed << std::setprecision(2) << pi; // 输出保留两位小数的pi
3. 缺省参数:让函数调用更灵活
3.1 缺省参数的基本规则
函数可以设定缺省参数,当调用时不传递该参数的值时,将采用预设的默认值。
void printMessage(std::string msg = "Default Message") {
std::cout << msg << std::endl;
}
// 不传递参数调用
printMessage(); // 输出"Default Message"
// 传递参数调用
printMessage("Custom Message"); // 输出"Custom Message"
- 缺省参数可以有多个,但必须从右向左依次设置,调用时不可跳过前面未给定值的缺省参数直接为后面的参数赋值。
3.2 半缺省参数
对于函数参数列表,可以部分缺省,这种情况下也只能从右至左开始缺省。
3.3 缺省参数的实际用途
缺省参数能够提高函数调用的灵活性,简化代码。比如在ST类初始化函数中提供一个官方推荐的初始大小:
class ST {
public:
ST(ST* ps, int n = 10); // 定义ST类的构造函数,n的缺省值为10
};
这样在创建ST对象时,如果不特别指定大小,则会使用默认值10。