C++类和对象(5)static修饰的静态成员变量函数

news2024/11/20 9:20:04

1.静态成员函数和静态成员变量的引入

(1)我们通过以下面的这个例子逐步引出静态的成员变量和成员函数:

我们自己定义一个类,使用这个类创建对象,我们应该如何判断在这个程序执行的过程中,创建了多少个对象,有几个对象是正在使用的。

 (2)上面的这个代码就可以进行判断正在使用的对象的个数和创建的对象的个数,我们是定义了一个n用来记录创建的对象的个数,我们定义了一个m用来记录正在使用的对象个数;

(3)我们在这个程序里面是写了4个函数,3个是默认的函数,1个就是我们自己定义的func函数,当执行默认构造函数和拷贝函数的时候,就让nm都加加,当执行析构函数的时候,就让m--,说明已经有一个对象被销毁了;最后再打印输出nm的数值;

(4)在这个过程中,我们有3组打印输出的结果,我们知道 m打印的结果一直都是2,说明正在使用的对象就是2个,n打印的结果在变化,说明一直有对象被创建;

(5)第一次的打印结果两个2很容易理解, 创建2个对象,执行默认构造函数,正在使用的对象个数是2,所以打印结果是两个2;

(6)A()这个我们之前提到过,这个就是一个匿名的对象,我们只需要记住匿名对象在进行创建的时候,在外观上面和默认的构造函数长的是一样的,所以这个时候创建的对象的个数除了前面的a1,a2还有我们现在的匿名对象A(),就是创建了3个对象,但是匿名对象的生命周期就在创建的那一行,所以在执行cout的时候,这个匿名对象的生命周期已经结束了,并不是正在使用的,所以m的值还是2;

(7)当我们调用func函数的时候,打印的结果显示n=5说明这个时候创建了5个对象,为什么会比第二次打印时候的3又多了2个呢?因为我们调用了func这个函数,a1这个实参传递给aa这个形参执行拷贝构造函数,这个时候需要创建对象,而且返回的时候,因为是传值返回,我们需要创建一个对象作为临时变量,所以又要创建一个对象,综上所述,一共是创建了5个对象;

(8)如果在func函数里面,我们是传引用返回,这个时候就不会生成这个临时的对象,这个时候的n就是4;如果我们使用传引用返回而且形参也是引用的,这个时候就不会执行拷贝构造函数,这个时候n=3;当然因为这个地方的aa这个返回值是出了作用域就会销毁的,并不符合传引用返回的条件,我们在这里只是说明问题,传引用返回实际上是不规范的;

这个过程我们好像并没有使用到静态的成员变量和成员函数,下面我们们将在这个题目的基础上面引入

2.为什么会存在静态的成员变量和成员函数

(1)上面的写法是有缺陷的,什么缺陷呢?

我们首先要理解的就是C++的一个很重要的特点就是封装性,但是这个里面我们定义的n和m都是全局的变量,很容易被修改破坏,因此我们可以把这两个变量放到类的里面去;

(2)放到类的里面之后,我们就要知道这个nm都是对象的,就是我们创建的任何一个对象都有n和m,现在我们想要这个n和m属于这个类,就要在前面加上static;

这个时候,我们在nm这两个成员变量的前面加上static之后,这两个成员变量就是静态成员变量,属于整个类了,而不是某一个单独的对象,这个时候我们会发现在等号的位置有报错;

这个就说明静态成员变量就不可以给缺省值了,为什么会这样?

因为我们在这个地方给的缺省值是传递给了初始化列表的,初始化列表是对对象进行初始化的,但是我们这里的静态成员变量是属于这个类的,不会走初始化列表的,所以就不应该给缺省值;

(3) 我们在类里面声明静态的成员变量,我们还是要进行定义的,我们可以在外面定义进行初始化的操作;因为这个时候静态的成员变量属于整个类域,所以我们在类外面定义的时候加上访问操作符;

(4)声明和定义完成之后,我们就可以进行打印输出成员变量的值,例如这里的A::m,a1.m都是可以访问到这些公有的成员变量的;但是我们不能直接打印nm这种,因为现在这个n和m已经在类域里面了,默认情况下我们找的时候只会在全局找,不会跑到类域里面去找的;

这个就相当于是有一个围墙,我们在打印的时候,就要看在全局里面是否存在这个变量,A::这种方式相当于是突破了围墙的限制,允许编译器到类域的里面去找,a1.这个也是可以突破围墙的,这个直接打印就不行;

(5) 我们上面还有一个实例,就是定义了一个A类的指针并且初始化为nullptr,我们使用ptr->n这样的方式也是可以突破围墙的限制,访问到静态的成员变量,并不会报错;

(6)上面的所有讨论都是建立在我们的静态成员变量都是public的,如果他们是private的,就都会报错,我们要想访问private这个里面的静态的成员变量,就需要使用和静态的成员变量相互对应的静态的成员函数;

(7)在private情况下面,我们可以在类里面定义getm这样的函数让函数的返回值是我们想要的n和m,但是如果我们是定义的匿名对象呢?

我们也可以使用A().print()的方式进行匿名对象函数的调用,但是这个会影响我们的判断,因为这个匿名对象调用print函数会创建一个新的对象,但是这个对象的创建是没有必要的;

(8)这个时候我们就可以在函数的前面加上static这样的话函数就成为了静态的成员函数;

静态的成员函数的特点是没有this指针,我们之前的那些普通函数有this指针(就是我们使用A这个类创建一个对象a1,我们使用a1.print()就可以调用这个函数,这个函数里面是有this指针接受这个传递过来的对象的);

现在的静态的成员函数,我们可以直接使用A::print()进行匿名对象的函数的调用,但是匿名函数里面不可以调用非静态的变量,因为非静态的变量的调用需要这个函数有this指针,但是静态的成员函数没有this指针。

(9)静态成员函数的限制就是不能访问非静态的成员变量,为什么非静态的需要this指针呢?

因为我们知道静态的成员变量是在类里面的,属于类域,但是非静态的就是属于某个对象的,我们要想使用这个非静态的变量,我们就要适用对象进行使用,但是有对象就有this指针 ,相当于我们的非静态的变量需要this但是静态成员函数没this所以不可在静态函数里面使用非静态的变量。

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

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

相关文章

Measurement and Analysis of Large-Scale Network File System Workloads——论文泛读

ATC 2008 Paper 分布式元数据论文阅读笔记整理 问题 网络文件系统在当今的数据存储中发挥着越来越重要的作用。使用网络文件系统可以降低管理成本,从多个位置可靠地访问的数据。这些系统的设计通常以对文件系统工作负载和用户行为的理解为指导[12,19&a…

Windows密码破解常见手段

mimikatz导出lsass破解 如果域管在成员机器上登录过,那么密码机会保存到lsass.exe进程当中,可以通过mimikatz读取密码 用本地管理员登录本地机器 导出hash reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCred…

四十九坊股权设计,白酒新零售分红制度,新零售策划机构

肆拾玖坊商业模式 | 白酒新零售体系 | 新零售系统开发 坐标:厦门,我是易创客肖琳 深耕社交新零售行业10年,主要提供新零售系统工具及顶层商业模式设计、全案策划运营陪跑等。 不花钱开3000多家门店,只靠49个男人用一套方法卖白酒…

使用scrollIntoView滚动元素到可视区域

1. 实现效果 点击顶部标签栏,让对应的内容出现在可视区域: 2. scrollIntoView () scrollIntoView 是一个内置的 JavaScript 方法,用于将元素滚动到视口可见的位置。它通常用于用户界面中,以便用户能轻松看到特定的元素。此方…

搭建Docker私服镜像仓库Harbor

1、概述 Harbor是由VMware公司开源的企业级的Docker Registry管理项目,它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 Harbor 的所有组件都在 Dcoker 中部署,所以 Harbor 可使用 Docker Compose 快速部署。 …

实战中使用 QEMU 进行内网穿透

前言 阅读 https://xz.aliyun.com/t/14052 《使用 QEMU 进行内网穿透?》 https://securelist.com/network-tunneling-with-qemu/111803/ 《Network tunneling with… QEMU?》 我将此项技术应用到实战中,取得不错的效果,但是也遇到很多坑&am…

Redis 实战之监视器

监视器 成为监视器向监视器发送命令信息总结 成为监视器 发送MONITOR 命令可以让一个普通客户端变为一个监视器, 该命令的实现原理可以用以下伪代码来实现: def MONITOR():# 打开客户端的监视器标志client.flags | REDIS_MONITOR# 将客户端添加到服务器…

【LeetCode:2391. 收集垃圾的最少总时间 + 二分】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

用python进行接口测试(详细教程)

前言 其实我觉得接口测试很简单,比一般的功能测试还简单,现在找工作好多公司都要求有接口测试经验,也有好多人问我什么是接口测试,本着不懂也要装懂的态度,我会说:所谓接口测试就是通过测试不同情况下的入…

4.5网安学习第四阶段第五周回顾(个人学习记录使用)

本周重点 ①部署域环境(Win2008) ②域组策略 ③域内信息收集 ④(重点)哈希传递攻击PTH ⑤MS14-068 提权漏洞 ⑥黄金票据伪造 ⑦白银票据伪造 ⑧ZeroLogon (CVE-2020-1472) 漏洞复现 本周主要内容 ①部署域环境(Win2008)…

【信道编码】2 卷积码、状态转移图、状态转移表、网格表示和码字路径

【信道编码】2 卷积码、状态转移图、状态转移表、网格表示和码字路径 写在最前面例题先行,原理随后示例:输入为01011100状态转移表状态转移图 卷积码的原理原理与结构工作流程误差纠正 (2,1,2)卷积编码器工作原理结构和示例状态转…

微信小程序按钮去除边框线

通常我们去掉按钮边框直接设置 border:0 但是在小程序中无效,设置outline:none也没用,当然可能你会说加权重无效 实际上该样式是在伪元素::after内,主要你检查css 还看不到有这个关系,鹅厂就是坑多 类样式::after {border: non…

odoo16 图标替换系列

1、网友标签标签 修改文件:addons/web/static/src/webclient/webclient.js 修改内容: 我把 "odoo" 替换成了 "RH" this.title.setParts({ zopenerp: "RH" }); // zopenerp is easy to grep2、修改登陆界面 技术/视图/L…

代码复现|subprocess.run()导致报错“FileNotFoundError: [WinError 2] 系统找不到指定的文件“

一 问题描述 记录复现(windows平台下,机器学习算法)代码遇到的问题。 根据控制台信息提示,定位到问题所在:sp.run()导致报错“FileNotFoundError: [WinError 2] 系统找不到指定的文件“。 定位报错位置如下&#xff0c…

PyQt5中的组件

文章目录 1. 简介2. QCheckBox3. QPushButton4. QSlider5. QProgressBar6. QCalendarWidget7. QPixmap8. QLineEdit9. QSplitter10. QComboBox11. 总结 1. 简介 在PyQt5中,有许多不同类型的组件,可以用于构建各种GUI界面。以下是一些常见的PyQt5组件&am…

读写备份寄存器BKP与实时时钟RTC

文章目录 读写备份寄存器接线图代码 RTC实时时钟接线图代码 读写备份寄存器 接线图 即接个3.3v的电源到VBT引脚 代码 代码效果:第一次写入备份寄存器,下载程序后再注释掉,再进行下载,之前写入的数据还会保存在备份寄存器中&am…

Java基础入门day48

day48 JDBC调用关系 tomcat 简介 tomcat是Apache下的一个核心项目,免费开源,支持servlet和jsp。 tomcat技术先进,性能稳定,目前比较流行的web应用服务器 安装 官网: Apache Tomcat - Welcome! 下载 tomcat8.5 解压&a…

leetcode——链表的中间节点

876. 链表的中间结点 - 力扣(LeetCode) 链表的中间节点是一个简单的链表OJ。我们要返回中间节点有两种情况:节点数为奇数和节点数是偶数。如果是奇数则直接返回中间节点,如果是偶数则返回第二个中间节点。 这道题的解题思路是&a…

使用Three.js绘制快速而逼真的水

本文将利用GPUComputationRenderer来实现水波纹的绘制,相似的案例可以看threejs官方的GPGPU Water示例。更多精彩内容尽在数字孪生平台。 什么是 GPGPU GPGPU代表通用图形处理单元(General-Purpose Graphic Processing Unit),意思…

护肤升级:如何选择最适合您的AI皮肤技术解决方案?

在不断变化的护肤行业中,人工智能技术的整合已经彻底改变了企业满足个人护肤需求的方式。了解人工智能在美容行业的重要性以及提供的解决方案,是选择最合适的解决方案至关重要的。领先的主要参与者之一是玩美移动,他们提供了一套全面的AI皮肤…