<!--markdown-->## 一、作用域分类与同名变量遮蔽规则

1. 作用域的三大分类

(1)全局作用域

  • 定义:在所有函数、代码块之外定义的变量/函数,拥有全局作用域。
  • 核心特性:

1. 在整个程序的所有函数、代码块中都可以访问(除非被同名局部变量遮蔽);

2. 生命周期伴随程序全程,程序启动时创建,结束时销毁。

  • 示例:

cpp

int x = 10; // 全局变量,全局作用域

void func() {

int x = 20; // 局部变量,遮蔽全局x

cout << x; // 优先访问局部变量,输出20

}

int main() {

func();

cout << x; // 无同名局部变量,访问全局变量,输出10

return 0;

}

(2)局部作用域(函数作用域)

  • 定义:在函数内部定义的变量,拥有局部作用域,也叫函数作用域。
  • 核心特性:

1. 仅在当前函数内部可访问,函数外部无法访问;

2. 函数执行时创建,执行结束后销毁;

3. 若与全局变量同名,局部变量会遮蔽全局变量,函数内默认访问局部变量。

(3)块作用域(复合语句作用域)

  • 定义:在{}包裹的代码块(复合语句)内定义的变量,拥有块作用域,是局部作用域的子集。
  • 核心特性:

1. 仅在当前{}代码块内可访问,代码块结束后变量立即销毁;

2. 若与外层代码块、全局变量同名,内层块变量会遮蔽外层变量,块内默认访问内层变量。

  • 示例:

cpp

int a = 1; // 全局作用域

void test() {

int a = 2; // 函数局部作用域,遮蔽全局a

{

int a = 3; // 块作用域,遮蔽外层a

a++; // 仅修改内层块的a,变为4,块结束后该变量销毁

}

a++; // 修改函数局部的a,变为3

cout << a << " "; // 输出3

}

int main() {

test();

cout << a; // 输出全局的1

return 0;

}

2. 核心规则:就近原则(名字遮蔽)

当不同作用域存在同名变量时,编译器会优先选择当前所在的最小作用域内的变量,外层、全局的同名变量会被遮蔽,默认无法直接访问。

  • 访问优先级:内层块作用域 > 函数局部作用域 > 全局作用域。

---

二、全局作用域解析符 ::

1. 核心作用

当局部变量遮蔽了全局同名变量时,使用::变量名的格式,可以强制访问全局作用域内的变量,绕过就近原则的遮蔽效应。

2. 语法格式

cpp

::全局变量名

3. 示例

cpp

int value = 100; // 全局变量

void print1() {

int value = 50; // 局部变量,遮蔽全局value

cout << value << " "; // 优先访问局部变量,输出50

cout << ::value << " "; // 强制访问全局变量,输出100

}

void print2() {

cout << value << " "; // 无同名局部变量,直接访问全局,输出100

}

int main() {

print1();

print2();

return 0;

}

---

三、函数的作用域与前向声明规则

1. 核心规则

C++中,函数必须先声明/定义,后调用。函数的作用域从它的声明/定义位置开始,到程序文件末尾结束。

  • 如果在调用函数时,编译器还没有看到该函数的声明或定义,会直接报编译错误:找不到函数。

2. 示例

cpp

// 错误写法:调用在前,定义在后,无前置声明

int main() {

greet(); // 调用点编译器未见过greet函数,编译报错

return 0;

}

void greet() { // 函数定义在调用之后

cout << "Hello!" << endl;

}

3. 两种正确写法

(1)函数定义放在调用之前

cpp

// 先定义,后调用,符合规则

void greet() {

cout << "Hello!" << endl;

}

int main() {

greet();

return 0;

}

(2)函数前向声明(声明在前,定义在后)

cpp

// 先做前向声明,告知编译器函数的存在

void greet();

int main() {

greet(); // 编译器已见过函数声明,调用合法

return 0;

}

// 后完成函数定义

void greet() {

cout << "Hello!" << endl;

}

---

四、考点

1. 易错点1:局部变量同名初始化的未定义行为

错误代码

cpp

int x = 10; // 全局变量

void f() {

int x = x + 1; // 未定义行为,绝对不会输出11

cout << x << endl;

}

int main() {

f();

}

错误原因

在局部变量int x的定义语句中,=右侧的x会被编译器优先匹配当前正在定义的局部变量x,而非全局变量x。此时局部变量x还未完成初始化,属于未定义行为,程序结果不可预测。

2. 易错点2:作用域 ≠ 生命周期

  • 作用域:变量可以被访问的代码范围,是编译期的概念;
  • 生命周期:变量在内存中存在的时间,是运行期的概念。
  • 高频误区:块作用域内的变量在块结束后就被销毁,即使通过指针拿到了它的地址,也无法合法访问,会触发未定义行为。

3. 易错点3::: 仅能访问全局变量

:: 只能用于访问全局作用域的变量,无法用它访问外层函数、外层代码块中的同名局部变量。

4. 易错点4:全局变量的重复定义

全局作用域内,同名的全局变量只能定义一次,多次定义会触发编译错误;而不同局部作用域内的同名变量互不影响。

---

五、考点速记表

题目核心场景核心规则正确结论
全局与局部同名变量就近原则,局部优先函数内默认访问局部变量
嵌套块内同名变量内层块优先遮蔽外层块内仅修改内层变量,不影响外层
访问被遮蔽的全局变量用::全局变量名强制访问::value可获取全局作用域的value
函数调用在前、定义在后必须先声明/定义后调用无前置声明会直接编译报错
局部变量定义时用自身初始化优先匹配当前局部变量,未初始化未定义行为,结果不可预测