从C学C++(7)——static成员

从C学C++(7)——static成员

若无特殊说明,本博客所执行的C++标准均为C++11.

static成员和成员函数

对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量。比如说统计某种类型对象已创建的数量。

通常在C中使用全局变量来实现,如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量,这时我们可以用类的静态成员来解决这个问题。

static数据成员存在于类类型的每个对象中static数据成员独立该类的任意对象存在,它是与类关联的对象,不与类对象关联。

个人理解:把它等同于python中类成员就可以了,不过C++中使用static关键字其实说明它和一般静态变量一样,存在于.bss段或者.data段,生命周期是整个程序(不随着对象实例创建或者销毁),所以其是独立于类对象实例存在的,但只是C++编译器在语法上把它归类于某个类(本质在运行时和其他静态变量无异),需要我们使用类域或者对象实例去访问(这个功能就和python中的类成员基本一致)。

类的static成员

特点:
  • static成员的名字是在类的作用域中,因此可以避免与其它类成员或全局对象名字冲突
  • 可以实施封装,static成员可以是私有的,而全局对象不可以
  • 阅读程序容易看出static成员与某个类相关联,这种可见性可以清晰地反映程序员的意图。
定义和注意事项
  • static成员需要在类定义体外进行初始化与定义。

    这个还好理解,因为类定义其实和C中结构类型声明是类似的,它只是声明了一种类似,因此,它的static 成员也只是声明里面有一个static 而已,真正这个独立于类对象实例的static 成员总得找个地方定义它(毕竟它和一般的成员不一样,一般的成员跟随着对象的定义而创建(分配内存空间))。

  • 特殊的整型static const成员:整型static const成员可以在类定义体中初始化和定义。(个人感觉更像是个语法糖,平时还是不用为好,而且只有整形可以,浮点和其它类型不可以,所以还是不用为好)。

枚举常量类型

在类中定义的枚举常量类型类似于static const 成员,是常量,而且被所有对象共享,属于类。

类的static成员函数

  • static 成员函数没有隐含的this指针。

    因为是类成员函数,不是任何一个特定对象的成员函数,所以自然没有隐含的this指针,也就意味着,在静态成员函数中,没有办法直接访问其他非静态成员(函数)。

  • 静态成员函数不可以访问非静态成员。

  • 非静态成员函数可以访问静态成员。

    具体对象实例可以访问类变量,也可以访问类函数一个道理。因为static 声明的成员(函数)是所有类共享的。

类/对象实例的大小计算

  • 类大小计算遵循前面学过的结构体对齐原则。
  • 类的大小与数据成员有关与成员函数无关。
  • 类的大小与静态数据成员(函数)无关。
  • 虚函数对类的大小的影响:会使类对象多4个字节的大小,用于存放虚表指针。
  • 虚继承对类的大小也会有影响。

static用法总结

函数内部修饰变量使其生存期为整个程序(C也一样)

用于函数内部修饰变量,即函数内的静态变量这种变量的生存期长于该函数,使得函数具有一定的"状态”。使用静态变量的函数一般是不可重入的,也不是线程安全的,比如strtok(3)

函数外部修饰变量使其限制于该文件(C也一样)

用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。专业的说法叫“具有internal linkage”(简言之:不暴露给别的translation unit,C/C++中最小编译单元为文件)

修饰类的数据成员使其成为类成员(C没有)

用于修饰类的数据成员,即所谓"静态成员”。这种数据成员的生存期大于class的对象(实例/instance)。静态数据成员是每个class有一份,普通数据成员是每个instance 有一份。

修饰类的成员函数使其成为类方法(C没有)

用于修饰class的成员函数,即所谓“静态成员函数”。这种成员函数只能访问静态成员和其他静态成员函数,不能访问非静态成员和非静态成员函数。

四种对象的作用域和生存期

栈对象

  • 隐含调用构造/析构函数(程序中没有显示调用)
  • 作用域为所属的{} 的块作用域内。
  • 生存期跟随所属函数的执行(分配空间)和退出(释放空间)。

堆对象

  • 隐含调用构造/析构函数(程序中没有显示调用)。
  • 作用域为所属的{} 的块作用域内。
  • 生存期取决于用户何时delete

全局对象、静态全局对象

  • 全局对象的构造先于main函数(这个对于支持嵌入式的C++编译器,会在进入main函数前的启动汇编代码中插入执行如__libc_init_array() 等的全局对象初始化函数链表执行)。
  • 已初始化的全局变量或静态全局对象存储于.data段中。
  • 未初始化的全局变量或静态全局对象存储于.bss(Block Started by Symbol)段中。
  • 全局对象和静态对象的生存期都是整个程序执行期间。

静态局部对象

  • 已初始化的静态局部变量存储于.data段中。
  • 未初始化的静态局部变量存储于.bss段中。
  • 对于静态局部变量,如果是内置类型(整形、浮点等),对象在编译时就初始化好在.data段中了,但对于静态局部的(我们自己定义的)类对象实例,其初始化是在代码运行时完成的。(这个好理解,虽然其存在于.data段而非栈上,但由于类对象实例初始化时需要执行构造函数,而编译器是没有办法执行函数的,只有运行到这段代码的时候才能执行构造函数,所以其初始化必须推迟到运行时刻)。

static 和单例模式

单例模式

设计模式的一种:保证一个类只有一个实例,并提供一个全局访问点。(目前暂时没有想到其的用处,按照之前的经验,感觉可能在对硬件封装时可能会有用,毕竟底层真实的硬件可能只有一个)。

在C++中设计单例模式需要注意:禁止构造函数、拷贝函数和=运算符,并提供共一个全局的访问点

使用static 局部对象和引用返回实现单例模式

class Singleton{
public:static Singleton& getInstance() {static Singleton instance; // 局部静态变量,保证只创建一次return instance;}~Singleton() {std::cout << "Singleton destroyed." << std::endl;}
private:Singleton(const Singleton& other); // 禁止拷贝构造Singleton& operator=(const Singleton& other); // 禁止赋值操作Singleton() {std::cout << "Singleton created." << std::endl;}
};

static 局部对象(利用其生存期为整个程序),且static 局部对象只会初始化一次的特性。通过返回引用,保证每次getInstance() 函数返回的都是同一个静态局部对象。需要注意,这里在调用函数的时候,必须使用引用来接收返回值(如果使用对象的话,这里会发生从引用到对象的赋值,而我们已经将拷贝构造函数声明为private,因此会报错,达到单例模式的目的)。

同时,因为返回的是引用,所以不存在多个对象释放的时候出现空指针的问题,在程序结束的时候,只有静态局部变量被释放一次,其他都是引用,不存在释放多次的问题。

Singleton& s1 = Singleton::getInstance(); // 获取单例实例
Singleton& s2 = Singleton::getInstance(); // 再次获取同一实例

const 成员函数/对象和mutable

const 成员函数

  • const成员函数不会修改对象的状态。

  • const 成员函数只能访问数据成员的值,不能修改它的值。

  • 需要注意const 成员函数是在函数声明和函数体之间加上const 关键字

    class Test{
    public:int get_x() const{ //这才是const成员函数return x; //且const成员函数内部不能修改数据成员的值}const int get_x1(){return x; // 这个函数只是一个返回const int 类型的成员函数而已,不是const成员函数}
    private:    int x
    }
    

const 对象的使用

  • 如果把一个对象指定为const,就是告诉编译器不要修改它。

  • const对象的定义:const 类名 对象名(参数表);

  • const 对象定义的时候默认会把不会修改内部变量的成员函数定义为const 成员函数,而那些修改到内部变量的成员函数则是非const 的,因此,如果const 对象调用那些非const 成员函数则会报错。

    这个好理解,因为成员函数默认是会传入一个this指针,那些要修改内部对象的成员函数传入的指针是非const的,而const对象传入自身指针是const类型,对C++来说,没有显式使用const_cast<>() 去除const 属性,是不可能完成const到非const的类型转换的。

mutable 关键字

如果我们需要定义个const对象,但这个对象中可能只需要一两个成员是需要被外界配置修改的,这个时候可以使用 mutable 关键字,因为,mutable 修饰的数据成员即使在const对象或在const成员函数中都可以被修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84810.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84810.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型和ollama一起打包到一个docker镜像中

如何将大模型镜像和 Ollama 镜像打包在一个 Docker 镜像中 最近工作中有个需求是将ollama和大模型一起打成一个镜像部署&#xff0c;将自己的操作步骤分享给大家。将大模型与 Ollama 服务打包在同一个 Docker 镜像中&#xff0c;可以简化部署流程并确保环境一致性。下面详细介…

2025年渗透测试面试题总结-攻防研究员(应用安全)(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 攻防研究员(应用安全) 一、基础部分 1. HTTP状态码对比 2. HTTP请求方法核心作用 3. 网络分层协议速查表…

SpringBoot新闻项目学习day3--后台权限的增删改查以及权限管理分配

新增管理员修改管理员删除管理员登录 新增管理员 1.点击新增按钮打开一个对话框 2.确定新增对话框要显示哪些内容 3.提交 4.后端处理、保存 5.响应前端 vue代码 <template><!-- 新增代码内容是比较多的,建议抽取出来,定义到一个独立的vue文件中在列表组件中导入…

算法导论第二十五章 深度学习的伦理与社会影响

第二十五章 深度学习的伦理与社会影响 技术的光芒不应掩盖伦理的阴影 随着深度学习技术在各领域的广泛应用&#xff0c;其引发的伦理和社会问题日益凸显。本章将深入探讨这些挑战&#xff0c;并提供技术解决方案和最佳实践&#xff0c;引导读者构建负责任的人工智能系统。 25.…

Linux中ansible模块补充和playbook讲解

一、模块使用 1.1 Yum模块 功能&#xff1a;管理软件包&#xff0c;只支持RHEL&#xff0c;CentOS&#xff0c;fedora&#xff0c;不支持Ubuntu其它版本 参数说明name要操作的软件包名称&#xff0c;支持通配符&#xff08;如 httpd, nginx*&#xff09;&#xff0c;也可以是…

唐代大模型:智能重构下的盛世文明图谱

引言&#xff1a;当长安城遇见深度学习 一件唐代鎏金舞马衔杯银壶的虚拟复原品正通过全息投影技术演绎盛唐乐舞。这个跨越时空的场景&#xff0c;恰似唐代大模型技术的隐喻——以人工智能为纽带&#xff0c;连接起长安城的盛世气象与数字时代的文明重构。作为人工智能与历史学…

国产ARM/RISCV与OpenHarmony物联网项目(三)网关设备控制

一、设备控制界面与功能设计 程序界面运行与设计效果如下: 设备控制相关程序调用关系图如下&#xff1a; 其中device_control.html程序为网页界面显示程序&#xff0c;led_alarm.cgi程序为光线数据的报警超限数据设置与管理&#xff0c;led_control.cgi程序功能为对Led灯的开…

微信小程序反编译实战教程

在实际渗透测试或安全分析中&#xff0c;经常会遇到微信小程序中的签名加密&#xff08;sign&#xff09;机制&#xff0c;这些机制大多具备防重放、防篡改的特性&#xff0c;导致我们在抓包时难以直接复现请求。 &#x1f50d; 另一方面&#xff0c;一些小程序的代码中往往会…

【NLP入门系列三】NLP文本嵌入(以Embedding和EmbeddingBag为例)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 博主简介&#xff1a;努力学习的22级本科生一枚 &#x1f31f;​&#xff1b;探索AI算法&#xff0c;C&#xff0c;go语言的世界&#xff1b;在迷茫中寻找光芒…

文心一言(ERNIE Bot):百度打造的知识增强大语言模型

1. 产品概述 文心一言&#xff08;ERNIE Bot&#xff09;是百度自主研发的知识增强大语言模型&#xff0c;于2023年3月16日正式发布&#xff0c;对标OpenAI的ChatGPT&#xff0c;具备文本生成、多模态交互、逻辑推理、中文理解等能力。该模型基于百度的飞桨深度学习平台和文心…

Java-49 深入浅出 Tomcat 手写 Tomcat 实现【02】HttpServlet Request RequestProcessor

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月13日更新到&#xff1a; AI炼丹日志-28 - Aud…

在VB.net中,文本插入的几个自定义函数

一、如果你是高手&#xff0c;一定“识货”&#xff0c;分享给你 二、可应用于文本插入的几种方式&#xff1a;6种 三、需要用到以下的几个函数&#xff1a; 上代码&#xff1a; Module TextModule <summary> 在指定位置插入文本 </summary> <p…

QC -io 服务器排查报错方式/报错: Failed to convert string to integer of varId variable!“

进断点控制台有报错之后&#xff0c;复制报错信息到 头部菜单栏 1.编辑 -> 2.Find/Replace ->3.Advanced Find ->4. Project“xxxxx” 能找到问题点 再分析定位 在排查报错时候&#xff0c;进入了这个报错&#xff0c;msgInfo "MyTcpRedis: Failed to conver…

c++中auto与decltype使用

在 C11及后续版本中&#xff0c;关键字auto和decltype都是用于类型推导的&#xff0c;但它们的使用场景和行为有所不同。 1. auto 关键字 作用 auto 用于自动推导变量的类型&#xff0c;由编译器根据初始化表达式来确定。 常见用法 // 基本用法 auto x 42; // int…

LabVIEW机器视觉零件检测

基于LabVIEW 图形化编程平台与机器视觉技术&#xff0c;构建集图像采集、处理、尺寸计算与合格性分析于一体的自动化检测方案。通过模块化硬件架构与自适应算法设计&#xff0c;实现对机械零件多维度尺寸的非接触式高精度测量&#xff0c;相比人工检测效率提升 12 倍&#xff0…

大数据治理域——实时数据开发

摘要 本文深入探讨了大数据治理域中的实时数据开发&#xff0c;重点介绍了流式数据处理的核心价值、特点、技术挑战、典型能力和应用场景。同时&#xff0c;详细阐述了流式技术架构&#xff0c;包括数据采集、处理、存储和服务等环节&#xff0c;并针对大促场景提出了相应的技…

Halcon/C# 图像窗口、读取图片及仿射变换

一、Halcon 清理窗口 清除图像窗口的显示。 dev_clear_window() 二、Halcon 读取图片 (一) 读取一张图片 read_image (Image, printer_chip/printer_chip_01)Image&#xff1a;&#xff08;输出参数&#xff09;读取到的图片变量名 第二个参数&#xff1a;图片路径&#xf…

Nginx 反向代理服务和安装docker-compose

Nginx 反向代理服务和安装docker-compose Nginx Proxy Manager 他是一个可视化的nginx的反向代理神器&#xff0c;动动手指轻松的配置Nginx&#xff0c;我们可以通过一些网页&#xff0c;即可完成网站的代理配置&#xff0c;无需在动手安装Nginx&#xff1b; dockoer-compose部…

FPGA基础 -- Verilog 锁存器简介

由浅入深地讲解 Verilog 中的锁存器&#xff08;Latch&#xff09;**&#xff0c;包括&#xff1a; 什么是锁存器&#xff08;定义与作用&#xff09;锁存器的分类&#xff08;透明锁存器 vs 边沿触发器&#xff09;Verilog 中锁存器的建模方式锁存器与触发器的区别锁存器的时…

Eclipse Memory Analyzer (MAT) 相关配置调整

一、JDK版本过低提示 已安装高于 jdk 17 的版本依旧提示 jdk 版本过低&#xff0c;打开MAT的安装目录&#xff0c;在配置文件 MemoryAnalyzer.ini 中添加配置指向JDK即可。新增两行配置&#xff1a; -vm D:/jdk_21.0.7/bin/javaw.exe //jdk安装路径 bin 目录下的javaw.exe二…