-
C++程序中出现的每个名字,只在某些可能不连续的源码部分中有效,这些部分被称为其作用域
-
在作用域内,能用
无限定名字查找
将名字与其声明关联起来
块作用域
int main()
{
int a = 0; // 第一个 'a' 的作用域开始
++a; // 名字 'a' 在作用域中并指代第一个 'a'
{
int a = 1; // 第二个 'a' 的作用域开始
// 第一个 'a' 的作用域间断
a = 42; // 'a' 在作用域中并指代第二个 'a'
} // 块结束,第二个 'a' 的作用域结束
// 第一个 'a' 的作用域恢复
} // 块结束,第一个 'a' 的作用域结束
int b = a; // 错误:名字 'a' 不在作用域中
try {
f();
} catch(const std::runtime_error& re) {
// re 的作用域开始
int n = 1; // n 的作用开始
std::cout << re.what(); // re 在作用域中
} // re 的作用域结束, n 的作用域结束
catch(std::exception& e) {
std::cout << re.what(); // 错误: re 不在作用域中
++n; // 错误: n 不在作用域中
}
Base* bp = new Derived;
if(Derived* dp = dynamic_cast<Derived*>(bp))
{
dp->f(); // dp 在作用域中
} // dp 的作用域结束
for(int n = 0; // n 的作用域开始
n < 10; // n 在作用域中
++n) // n 在作用域中
{
std::cout << n << ' '; // n 在作用域中
} // n 的作用域结束
函数形参作用域
const int n = 3;
int f1(int n, // 全局 'n' 的作用域间断
// 形参 'n' 的作用域开始
int y = n); // 错误:默认实参涉指了形参
int (*(*f2)(int n))[n]; // OK :函数形参 'n' 的作用域终止于其函数声明符的末尾
// 在数组声明符中,全局 n 在作用域中
// (这声明了一个返回(含有 3 个 int 元素的数组的指针)的函数的指针)
// 相反
auto (*f3)(int n)->int (*)[n]; // 错误:以形参 'n' 为数组边界
int f(int n = 2) // 'n' 的作用域开始
try // 函数 try 块
{
// 函数体开始
++n; // 'n' 在作用域中并指代函数形参
{
int n = 2; // 局部变量 'n' 的作用域开始
// 函数形参 'n' 的作用域中断
++n; // 'n' 在此块中指代局部变量
} // 局部变量 'n' 的作用域结束
// 函数形参 'n' 的作用域恢复
} catch(...) {
++n; // n 在作用域中并指代函数形参
throw;
} // 最后异常处理块结束,函数形参 'n' 的作用域结束
int a = n; // OK :全局 'n' 在作用域中
函数作用域
void f()
{
{
goto label; // label 在作用域中,尽管之后才声明
label:;
}
goto label; // label 忽略块作用域
}
void g()
{
goto label; // 错误: g() 中 label 不在作用域中
}
命名空间作用域
namespace N {
// N 的作用域开始(作为全局命名空间的成员)
int i; // i 的作用域开始
int g(int a) {
return a; } // g 的作用域开始
int j(); // j 的作用域开始
void q(); // q 的作用域开始
namespace {
int x; // x 的作用域开始
} // x 的作用域不结束
inline namespace inl {
// inl 的作用域开始
int y; // y 的作用域开始
} // y 的作用域不结束
} // i、g、j、q、inl、x、y 的作用域间断
namespace {
int l=1; // l 的作用域开始
} // l 的作用域不结束(它是无名命名空间的成员)
namespace N {
// i、g、j、q、inl、x、y 的作用域继续
int g(char a) {
// 重载 N::g(int)
return l+a; // 来自无名命名空间的 l 在作用域中
}
// int i; // 错误:重复定义( i 已在作用域中)
int j(); // OK :允许重复的函数声明
int j() {
// OK :定义先前声明的 N::j()
return g(i); // 调用 N::g(int)
}
int q(); // 错误: q 已在作用域中并有不同的返回类型
} // i、g、j、q、inl、x、y 的作用域间断
int main() {
using namespace N; // i、g、j、q、inl、x、y 的作用域恢复
i = 1; // N::i 在作用域中
x = 1; // N::(匿名)::x 在作用域中
y = 1; // N::inl::y 在作用域中
inl::y = 2; // N::inl 也在作用域中
} // i、g、j、q、inl、x、y 的作用域间断
类作用域
class X {
int f(int a = n) {
// 默认实参内的 X::n 在作用域中
return a*n; // 函数体内的 X::n 在作用域中
}
using r = int;
r g();
int i = n*2; // 初始化器内的 X::n 在作用域中
// int x[n]; // 错误:类体内的 X::n 不在作用域中
static const int n = 1;
int x[n]; // OK : 类体内的 X::n 现在在作用域中
};
//r X::g() { // 错误:类外成员函数内的 r 不在作用域中
auto X::g()->r {
// OK :尾随返回类型内的 X::r 在作用域中
return n; // 类外成员函数体内的 X::n 在作用域中
}
typedef int c; // ::c
enum {
i = 1 }; // ::i
class X {
char v[i]; // 错误:此处 i 指代 ::i,但 X::i 也存在
int f() {
return sizeof(c); // OK :成员函数体内在作用域中的是 X::c 而非 ::c
}
char c; // X::c
enum {
i = 2 }; // X::i
};
typedef char* T;
struct Y {
T a; // 错误:此处,T 指代 ::T,但 Y::T 也存在
typedef long T;
T b;
};