C++系列之static关键字

static关键字有什么作用?

这也算是面经中老生常谈的问题了,看来不懂的同学没有好好的刷面经啊。

那么本文就来好好解释一下这个问题。

C++的static关键字主要的功能有:改变作用域改变变量在内存模型中的存储位置。修饰不同的变量会有不同的效果,现在我们来一一说明。

先放总结:

(1)static修饰全局变量,该变量作用域由global变成当前文件

(2)static修饰全局函数,该函数作用域由global变成当前文件

(3)static修饰函数局部变量,该变量生命周期从原本贯穿函数调用期间,变成贯穿整个程序,但其作用域依然局限在所在函数作用域。

(4)static修饰类的成员变量或成员函数,称为静态成员,静态成员被类的所有对象共有。静态成员具有以下特性:

  • 静态成员被类的所有对象所共有
  • this指针无法指向静态成员
  • 静态函数无法更改或调用非静态成员
  • 静态成员可以直接用类调用,如:Family::static_var,Family::static_func()

为了方便,代码验证使用Visual Studio 2019,建议读者也把下面代码手敲运行一遍。

修饰全局变量

当一个变量被定义成全局变量时,该变量的作用域为global,全局变量可以跨文件使用。当用static修饰成员变量时,该变量的作用域仅在当前文件。

未用static进行修饰

测试代码如下:

c++ 复制代码
// file.cpp
int cs = 1;

// another_file.cpp
#include <iostream>

extern int cs;
int main() {
    std::cout << "全局变量cs=" << cs << std::endl;
    return 0;
}

测试实况:

输出结果:

使用static修饰全局变量

测试代码如下:

c++ 复制代码
// file.cpp
static int cs = 1;

// another_file.cpp
extern int cs;
int main() {
    std::cout << "全局变量cs=" << cs << std::endl;
    return 0;
}

测试实况:

输出结果:

IDE提示链接错误,这就是因为变量cs的作用域仅限file.cpp,在another_file.cpp无法访问到cs

结论

static关键字修饰全局变量时会使其作用域从全局变成当前文件范围。

修饰全局函数

static修饰全局函数时,效果和全局变量一样,也是将其作用域从全局变成了当前文件范围。

未使用static修饰

测试代码:

c++ 复制代码
// file.cpp
int add(int a, int b) {
    return a + b;
}

// another_file.cpp
#include <iostream>

extern int add(int a, int b);
int main() {
    std::cout << add(2, 3) << std::endl;
    return 0;
}

测试实况:

测试结果:

在another_file.cpp可以正常调用file.cpp中的全局函数。

使用static修饰全局函数

测试代码:

c++ 复制代码
// file.cpp
static int add(int a, int b) {
    return a + b;
}

// another_file.cpp
#include <iostream>

extern int add(int a, int b);

int main() {
    std::cout << add(2, 3) << std::endl;
    return 0;
}

测试实况:

测试结果:

链接失败。

结论

同全局变量一样,用static修饰全局函数后,该函数的作用域从全局变成当前文件。

修饰函数中的局部变量

用static修饰函数的局部变量时,延长局部变量的生命周期,使其贯穿整个程序。

c++ 复制代码
// test_func.cpp

#include <iostream>

void func() {
    int a = 1;
    static int b = 1;
    std::cout << "a=" << a++ << ", b=" << b++ << std::endl;   
}

int main() {
    for (int i = 0;i < 5; i++) {
        func();
    }

    return 0;
}

测试结果:

局部变量a,在每次函数调用都会被重新赋值,生命周期仅限于函数调用期间。

而被static修饰的局部变量b在每次函数调用后都会持续增加,函数调用结束后也不会被销毁,生命周期持续到程序结束。

结论

static修饰函数局部变量时,会延长该局部变量的生命周期,直到程序结束。

这是因为未被修饰的局部存在栈中,函数调用结束后,该栈空间会被回收,连带成员变量一起回收。

而被static的函数成员变量存在内存模型中的"常量区",该区域的变量会直到程序结束才会被销毁。

修饰类成员

被static类的成员变量或成员函数称为静态成员,该静态成员会归属于类,被所有该类实例化的对象共享。举个例子,静态成员就像家里的空调,是所有家庭成员共享的,所有家庭成员都能使用,且不独属于某个家庭成员。

但是静态成员有几个特点

(1)不能在静态成员函数修改非静态成员变量或者调用非静态成员函数

(2)静态成员可以直接用类访问:Family::air

(3)this指针无法指向静态成员:this->air 会报错

测试代码:

c++ 复制代码
#include <iostream>
#include <string>

class Family {
public:
    static int air; // 静态成员变量声明
    std::string role;

    Family(std::string role) : role(role) {}

    static void static_printAir() {
        std::cout << "全家一起用空调,当前 air=" << air << std::endl;
    }

    void printAir() {
        std::cout << this->role <<"使用空调," << "当前 air=" << air << std::endl;
    }
};

// 静态成员变量定义(必须在类外)
int Family::air = 20;

int main() {
    Family husband("丈夫");
    Family wife("妻子");

    Family::air++;
    Family::static_printAir(); // 输出: 当前 air=21

    husband.air++; // 修改静态成员变量
    husband.printAir(); // 输出: 当前 air=22

    wife.air++; // 再次修改静态成员变量
    wife.printAir(); // 输出: 当前 air=23

    husband.static_printAir(); // 类实例对象也可以调用静态成员函数

    return 0;
}

测试结果:

结论

静态成员被类的所有成员共同拥有

this指针无法指向静态成员

相关推荐
小林熬夜学编程29 分钟前
【高并发内存池】第八弹---脱离new的定长内存池与多线程malloc测试
c语言·开发语言·数据结构·c++·算法·哈希算法
曦月逸霜1 小时前
蓝桥杯高频考点——高精度(含C++源码)
c++·算法·蓝桥杯
敲上瘾1 小时前
高并发内存池(二):Central Cache的实现
linux·服务器·c++·缓存·哈希算法
SNAKEpc121382 小时前
在MFC中使用Qt(五):MFC和Qt的共存和交互
c++·qt·mfc
我们的五年2 小时前
【Linux系统】进程间通信-System V消息队列
linux·运维·服务器·c++
laimaxgg3 小时前
数据结构B树的实现
开发语言·数据结构·c++·b树·算法
mit6.8243 小时前
[Lc6_记忆化搜索] 最长递增子序列 | 矩阵中的最长递增路径
c++·算法·leetcode
双叶8369 小时前
(C语言)虚数运算(结构体教程)(指针解法)(C语言教程)
c语言·开发语言·数据结构·c++·算法·microsoft
牵牛老人11 小时前
C++设计模式-责任链模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
c++·设计模式·责任链模式
序属秋秋秋12 小时前
算法基础_基础算法【高精度 + 前缀和 + 差分 + 双指针】
c语言·c++·学习·算法