c++ static(详解)

news/2024/9/20 7:34:32 标签: c++, 开发语言

C++中,static关键字用于定义具有静态存储持续时间的变量或方法。它在不同上下文中有不同的含义,通常与变量的存储方式和作用域相关。static的主要作用是控制变量或函数的可见性和生命周期。

可以通过一个生活中的场景来形象化static的作用:

场景:

假设你是一位图书馆管理员,负责管理图书馆中每个人的借书记录。每次有新成员登记时,你都为他们创建一个新的借书账户,并记录他们借的书。但图书馆有一个总借书数的统计,也就是说,不管有多少个会员借书,所有人的借书数量都会加在一起,形成一个全馆的总借书数。

静态变量的作用:

  • 借书账户的个人记录:每个会员都有自己借书的记录(类似于类的普通成员变量),每个人只能看到自己借了几本书。
  • 图书馆的总借书数:图书馆有一个总借书数的统计,这个数字对所有会员来说是共享的(类似于static成员变量),每个会员借了一本书后,这个总数都会增加。

对应到C++代码:

#include <iostream>

using namespace std;

class LibraryMember{
public:
    int personalBorrowedBooks = 0; //个人借书记录

    static int totalBorrowedBooks; //总借书数(所有人共享)

    void borrowBook(){
        personalBorrowedBooks++; //总借书数增加
        totalBorrowedBooks++; //总借书数增加
    }
    void showBorrowInfo(){
        cout <<"You have borrowed " << personalBorrowedBooks << " books." << endl;
        cout <<"The liberary has loand out " << totalBorrowedBooks << " book in total." << endl;
    }

};

//初始化静态成员变量
int LibraryMember::totalBorrowedBooks = 0;

int main(){

    LibraryMember member1;
    LibraryMember member2;

    member1.borrowBook();  // member1借了1本书
    member2.borrowBook();  // member2借了1本书
    member1.borrowBook();  // member1又借了1本书

    cout << "memeber1 Info " << endl;
    member1.showBorrowInfo() ;  // 显示member1的信息
    cout << "memeber2 Info " << endl;
    member2.showBorrowInfo();  // 显示member2的信息

    return 0;
}

输出结果:

memeber1 Info 
You have borrowed 2 books.
The liberary has loand out 3 book in total.
memeber2 Info 
You have borrowed 1 books.
The liberary has loand out 3 book in total.

分析:

  1. 个人借书记录(非静态成员变量):每个LibraryMember对象有自己独立的借书记录。member1借了2本书,而member2借了1本书,他们各自的记录是独立的。
  2. 总借书数(静态成员变量):所有成员共享一个总借书数,不管是哪个成员借了书,这个总借书数都会增加。

静态的现实意义:

static 就像图书馆的总借书统计,它不会因为某个会员的加入或离开而被重新设置或注销,始终保持一个全局的、共享的状态。这类似于生活中我们对一些全局、共享数据的统计与追踪,所有人都可以贡献,但数据是统一维护的。

1. 静态成员变量

静态成员变量(类的静态变量)属于整个类,而不是某个具体的对象。它们在所有对象中共享,也就是说,不管创建了多少个类对象,静态成员变量在内存中只有一份,且对所有对象都是共用的。

  • 作用:用于存储类的全局状态,所有对象共享该状态。
class MyClass {
public:
    static int staticVar;
    MyClass() { staticVar++; }  // 每次创建对象时都会递增
};

int MyClass::staticVar = 0;  // 静态变量需要在类外初始化

int main() {
    MyClass obj1;
    MyClass obj2;
    cout << MyClass::staticVar;  // 输出 2
}

2. 静态成员函数

静态成员函数和静态成员变量类似,它们属于整个类,而不是某个对象。静态成员函数只能访问静态成员变量,不能访问非静态成员变量,因为非静态成员变量依赖于具体的对象实例。

  • 作用:用于不依赖对象的功能实现,比如操作静态成员变量。
class MyClass {
public:
    static int staticVar;
    static void printStaticVar() {
        cout << staticVar << endl;  // 可以访问静态变量
    }
};

int MyClass::staticVar = 0;

int main() {
    MyClass::printStaticVar();  // 直接通过类名调用静态函数
}

3. 静态局部变量

在函数内部,static 局部变量的生命周期贯穿整个程序的执行,而不仅仅是在函数调用期间。它在函数第一次被调用时初始化,并在程序的整个生命周期内保持其值。

  • 作用:用于需要在函数多次调用时保持其状态的场景。
void countCalls() {
    static int count = 0;  // 只初始化一次
    count++;
    cout << "This function has been called " << count << " times" << endl;
}

int main() {
    countCalls();  // 输出 1
    countCalls();  // 输出 2
    countCalls();  // 输出 3
}

4. 静态全局变量

static 修饰的全局变量(在函数或类外定义)只能在定义它的文件中访问,无法被其他文件访问。这是一种用于控制链接的方式,通常用于实现模块间的数据隔离,防止名称冲突。

  • 作用:用于在一个源文件中定义只对该文件可见的变量。
static int fileVar = 0;  // 只能在当前文件中使用

5. 静态函数(文件作用域)

类似于静态全局变量,static 修饰的函数只能在定义它的文件中使用。这在大型项目中非常有用,因为它可以防止不同文件中的函数名冲突。

  • 作用:用于限制函数的可见性,使其仅在定义的文件中可用。
static void helperFunction() {
    // 只能在当前文件中调用
}

6. 使用场景总结

  • 共享类成员:静态成员变量和静态成员函数在类的不同实例之间共享数据。
  • 维护函数状态:静态局部变量用于在函数调用之间保持状态。
  • 文件级作用域:静态全局变量和静态函数用于实现文件内的变量和函数封装,避免命名冲突。
  • 效率提升:静态成员函数可以在不创建对象的情况下直接调用,减少对象的开销。

static 在C++中用于控制变量或函数的生命周期作用域,在代码优化、模块化设计等方面发挥着重要作用。


http://www.niftyadmin.cn/n/5666817.html

相关文章

计算机毕业设计 奖学金评定管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Python 复制Excel 中的行、列、单元格

在Excel中&#xff0c;复制行、列和单元格是日常工作中经常需要进行的操作&#xff0c;它可以帮助你快速调整数据布局、复制数据模板或进行数据的批量处理。 本文将详细介绍如何使用Python将Excel中的行、列、或单元格范围复制到指定位置。 所需Python库 要使用Python操作Exc…

秋招自我介绍

1min 尊敬的面试官您好&#xff0c;感谢您百忙之中参加我的面试。我是来自北京大学的王峰。 在实习经历方面&#xff0c;我曾在美团和小米公司实习。在美团主要负责核身、质检、词云项目。 在核身项目中&#xff0c;完整的经历从0-1的项目上线过程 在质检项目中&#xff0c;进…

【内网渗透】最保姆级的春秋云镜Privilege打靶笔记

目录 flag1 flag2 flag3 flag4 flag1 fscan扫外网 访问./www.zip拿到源码 tools/content-log.php存在任意文件读取 根据提示读到Jenkins初始管理员密码 ./tools/content-log.php?logfile../../../../../../../../../ProgramData/Jenkins/.jenkins/secrets/initialAdminP…

问:JAVA中wait()和sleep()有哪些区别,知道不?

在Java中&#xff0c;wait方法和sleep方法是用于线程控制的两种不同机制&#xff0c;它们有着不同的用途和行为。 1. wait 方法 定义&#xff1a;wait 是 Object 类的方法&#xff0c;用于线程间的通信&#xff0c;通常与同步&#xff08;synchronized&#xff09;块/方法一起…

Java后端性能监控:使用JMX与Java Mission Control的深入解析

Java后端性能监控&#xff1a;使用JMX与Java Mission Control的深入解析 大家好&#xff0c;我是微赚淘客返利系统3.0的小编&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在Java后端开发中&#xff0c;性能监控是确保系统稳定和高效运行的关键。…

AI时代,服务器厂商能否打破薄利的命运?

文&#xff5c;刘俊宏 编&#xff5c;王一粟 AI大模型正在引发新一轮的“算力焦渴”。 近日&#xff0c;OpenAI刚发布的o1大模型再次刷新了大模型能力的上限。对比上一次迭代的版本&#xff0c;o1的推理能力全方位“吊打”了GPT-4o。更优秀的能力&#xff0c;来自与o1将思维…

【JAVA入门】Day47 - 线程

【JAVA入门】Day47 - 线程 文章目录 【JAVA入门】Day47 - 线程一、并发和并行二、多线程的实现方式2.1 继承 Thread 类的方式2.2 实现 Runnable 接口的方式2.3 利用 Callable 接口实现 三、Thread 类中常见的成员方法四、线程的调度和优先级4.1 抢占式调度4.2 优先级4.3 守护线…