出现在C++程序中的每个名称仅在源代码的某个可能不连续的部分中有效,称为其作用域。
Within a scope, unqualified name lookup can be used to associate the name with its declaration.
块作用域(block scope)
由块中的声明(复合语句)引入的变量的潜在作用域从声明点开始,到块的末尾结束。实际作用域与潜在作用域相同,除非有一个嵌套块的声明引入了相同的名称(在这种情况下,嵌套声明的整个潜在作用域被排除在外部声明的作用域之外):
int main(){
int a=0; //第一个a的作用域从这里开始
++a; //此时“a”指代第一个a
{
int a=1; //第二个a的作用域从这里开始,但是在这种情况下,嵌套声明的作用域被排除在了第一个a的作用域之外
a=42; //指代第二个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的作用域中
}catch(std:exception &e){ //re的作用域结束,n的作用域结束
std:cout<<re.what(); //报错,因为re不在作用域中
++n; //报错,因为n不在作用域中
}
The potential scope of a name declared in the init-statement of the for loop, in the condition of a for loop, in the range_declaration of a range for loop, in the init-statement of the if statement or switch statement (since C++17), in the condition of the if statement, while loop, or switch statement begins at the point of declaration and ends at the end of the controlled statement.
在for循环的init语句中,在for循环的条件下声明的名称的潜在范围,在for循环的RangeEx声明中,在if语句或开关语句(因为C++ 17)的init语句中,在if语句的条件下,while循环,或切换语句在声明点开始,结束于受控语句的结尾:
Base *bp=new Derivied;
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的作用域中
}
函数参数作用域
函数参数(包括lambda表达式的参数)或函数局部预定义变量的潜在作用域从其声明点开始:
- 如果最近的封闭函数声明符不是函数定义的声明符,则其潜在作用域以该函数声明符的结尾结束。
- 否则,它的潜在作用域将在函数try块的最后一个异常处理程序的末尾结束,如果没有使用函数try块,则在函数体的末尾结束。
const int n=3;
int f1(int n, //n的全局作用域被打断,参数n的作用域开始
int y=n); //这里会报错,因为默认变量引用了一个参数
int (*(*f2)(int n))[n]; //不会报错,因为函数参数n的作用域在其函数声明符的末尾结束
//而在数组声明符中,n位于全局变量的作用域中
//this declares a pointer to function returning a pointer to an array of 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的作用域均中止
}catch(...){
++n; //此时n在函数参数的作用域内
throw;
} //最后一个异常处理器结束,函数参数的作用域结束
int a=n; //现在n在全局作用域中