1、 作用域(Scope)
作用域(scope)是指一个标识符(比如变量名、函数名等)在程序中有效的一个区域。定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。
1)局部作用域(Local Scope)
在函数或代码块内定义的变量只能在该函数或代码块内部访问。一旦函数或代码块执行完毕,该变量即被销毁。
例如,
#include <iostream>
using namespace std;
int fn(int a){
int b,c; //a,b,c仅在函数fn()内有效
return a+b+c;
}
int main(){
int m,n; //m,n仅在函数main()内有效
return 0;
}
2)全局作用域(Global Scope)
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .cpp
和 .h
文件。在所有函数之外定义的变量在整个文件中都可访问。这种变量会在程序启动时分配内存,并在程序结束时释放。
例如,
#include <iostream>
using namespace std;
int a, b=3; //全局变量
void fn(){
cout << a << endl << b << endl;
}
int main(){
fn();
cout << a << endl << b << endl;
return 0;
}
3)类作用域(Class Scope)
类的成员变量和成员函数在类作用域内可见,类的成员可以通过对象或指针访问。
#include <iostream>
using namespace std;
class MyClass {
public:
int member; // 类作用域内的成员变量
void method() { // 类作用域内的成员函数
cout << "Method is called. Member value is: " << member << endl;
}
};
int main() {
MyClass obj; // 实例化对象
obj.member = 10; // 访问并设置成员变量
obj.method(); // 调用成员函数
return 0;
}
4)文件作用域(File Scope)
静态变量和函数在文件作用域内可见。文件作用域的变量和函数只能在定义它们的文件中访问。
// file_scope_example.cpp
#include <iostream>
using namespace std;
static int fileScopedVariable = 42; // 文件作用域变量
static void fileScopedFunction() { // 文件作用域函数
cout << "File scoped function. Variable value: " << fileScopedVariable << endl;
}
int main() {
fileScopedFunction(); // 调用文件作用域函数
return 0;
}
5)语句作用域(Statement Scope)
语句作用域(Statement Scope)指的是在特定语句块 { }
中定义的变量,其作用域仅限于该块内部。如 for
循环中的变量定义,只在该语句块内有效。
#include <iostream>
using namespace std;
int main() {
int x = 10; // 在 main 函数作用域内定义变量 x
cout << "x in main scope: " << x << endl;
{ // 进入新的语句作用域
int x = 20; // 在此作用域中定义一个新的 x,覆盖 main 中的 x
cout << "x in inner scope: " << x << endl;
} // 语句块结束,此作用域的 x 超出作用域被销毁
cout << "x back in main scope: " << x << endl; // 输出 main 函数作用域的 x
for (int i = 0; i < 3; ++i) { // 循环内的 i 仅在 for 语句作用域内有效
cout << "i in for loop scope: " << i << endl;
}
// cout << i; // 这里访问 i 会出错,因为 i 超出了 for 循环的作用域
return 0;
}
2、局部变量与全局变量的区别
1)局部变量是声明在块或者函数内部的变量。局部变量的作用域局限于该块或者函数。局部变量如果没有初始化,将包含垃圾数据。
2)全局变量是在所有块和函数之前声明的变量。全局变量对所有在它之后声明的函数有效。全局变量有默认值初始化,如0
。
注意:如果要调用另外一个文件中的全局变量,如果再声明一个同名的全局变量,那么编译器会因为重名报错,这个时候就要使用extern
变量。extern
声明告诉编译器这个变量的定义在其他文件中,所以并不会为它分配内存。
#include <iostream>
using namespace std;
int globalVar = 100; // 全局变量
void myFunction() {
int localVar = 10; // 局部变量
globalVar += 10; // 可以访问并修改全局变量
cout << "Inside myFunction - localVar: " << localVar << ", globalVar: " << globalVar << endl;
}
int main() {
int localVar = 5; // main 函数内的局部变量,与 myFunction 中的 localVar 不同
cout << "Inside main - localVar: " << localVar << ", globalVar: " << globalVar << endl;
myFunction(); // 调用 myFunction 函数
cout << "After calling myFunction - localVar: " << localVar << ", globalVar: " << globalVar << endl;
return 0;
}
3、静态局部变量和静态全局变量区别
1)非静态全局变量的作用域是整个源程序 ,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
2)静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。
3)示例代码
#include <iostream>
using namespace std;
// 静态全局变量,作用域仅限于当前文件
static int globalCounter = 0;
// 非静态全局变量,可以被其他文件访问(如果有外部链接)
int nonStaticGlobalCounter = 0;
void staticLocalExample() {
// 静态局部变量,作用域仅限于此函数内,但生命周期贯穿程序始终
static int localCounter = 0;
localCounter++;
cout << "Static Local Counter: " << localCounter << endl;
}
void staticGlobalExample() {
globalCounter++;
cout << "Static Global Counter: " << globalCounter << endl;
}
int main() {
cout << "Calling staticLocalExample() multiple times:" << endl;
staticLocalExample(); // 第一次调用,localCounter = 1
staticLocalExample(); // 第二次调用,localCounter = 2
staticLocalExample(); // 第三次调用,localCounter = 3
cout << "\nCalling staticGlobalExample() multiple times:" << endl;
staticGlobalExample(); // 第一次调用,globalCounter = 1
staticGlobalExample(); // 第二次调用,globalCounter = 2
staticGlobalExample(); // 第三次调用,globalCounter = 3
return 0;
}
4、C++命名空间(Namespace)
命名空间用于组织代码,以防止名称冲突。C++允许通过命名空间将函数、类和变量分组。常用的命名空间是 std,其中包含C++标准库的所有内容。
1)命名空间的定义
访问命名空间中作用域内实体
命名空间名::命名空间成员名;
标准命名空间std
C++标准库所有标识符都是在一个名为std的命名空间中定义的,或者说标准头文件中函数、类和对象模板是在命名空间std
中定义的。可以在文件开头加入 using namespace std;
使用时就可以不写std::
。
使用示例:
#include <iostream>
using namespace std;
namespace Animal
{
void Show()
{
//如果上面没using namespace std; 则使用cout需要std::cout
cout << "Animal" << endl;
}
}
namespace Person
{
void Show()
{
//如果上面没using namespace std; 则使用cout需要std::cout
cout << "Person" << endl;
}
}
int main()
{
Animal::Show();
Person::Show();
return 0;
}
2)使用命名空间
完全限定名称:在使用命名空间中的变量或函数时,使用 命名空间名称::元素名称
的方式。
MyNamespace::myFunction();
使用 using
指令:使用 using namespace
指令可以将整个命名空间的内容引入当前作用域。
using namespace MyNamespace;
myFunction(); // 可以直接调用,不需要加前缀
使用 using
声明:只将命名空间中的特定元素引入当前作用域。
using MyNamespace::myFunction;
myFunction(); // 可以直接调用
3)匿名命名空间
匿名命名空间是没有名称的命名空间,其内容仅在定义它的文件中可见。这是一种创建文件作用域的有效方式。
#include <iostream>
namespace {
// 匿名命名空间内的变量和函数
int hiddenVar = 42;
void hiddenFunction() {
std::cout << "This is a function inside an anonymous namespace." << std::endl;
}
}
void testFunction() {
// 可以在当前编译单元中访问匿名命名空间内的内容
std::cout << "Value of hiddenVar: " << hiddenVar << std::endl;
hiddenFunction();
}
int main() {
testFunction();
// 无法从外部直接访问匿名命名空间内的内容
// std::cout << hiddenVar; // 错误:不能直接访问匿名命名空间中的 hiddenVar
// hiddenFunction(); // 错误:不能直接调用匿名命名空间中的 hiddenFunction
return 0;
}
4)嵌套命名空间
C++17 引入了嵌套命名空间的简化语法,使得定义嵌套命名空间更简洁。
#include <iostream>
namespace OuterNamespace {
namespace InnerNamespace {
void display() {
std::cout << "Inside InnerNamespace!" << std::endl;
}
}
}
// 使用 C++17 的简化嵌套命名空间语法
namespace OuterNamespace::NestedNamespace {
void show() {
std::cout << "Inside NestedNamespace!" << std::endl;
}
}
int main() {
// 调用 InnerNamespace 中的函数
OuterNamespace::InnerNamespace::display();
// 调用 NestedNamespace 中的函数
OuterNamespace::NestedNamespace::show();
return 0;
}