018 - C++ 类和结构体中的静态(static)

news2024/9/28 23:23:35

上一期我们讨论了 C++ 中的 static 关键字以及它在类或结构体之外的意义。本期我们讨论 static 在一个类或一个结构体中的具体情况。

先了解这些

在几乎所有面向对象的语言中,静态在一个类中意味着特定的东西。这意味着在类的所有实例中,这个变量只有一个实例。如果我创建一个名为 Entity 的类,然后不断创建 Entity 实例,我仍然只会得到那个变量的一个版本。相对应的,如果某个实例改变了这个静态变量,它会在所有实例中反映这个变化。

正因为如此,通过类实例来引用静态变量是没有意义的。因为这就像是类的全局实例。

静态方法也是一样,无法访问类的实例。静态方法不需要通过类的实例就可以被调用。而在静态方法内部,你不能写引用到类实例的代码,因为你不能引用类的实例。

例子时间

让我们来看一下例子。

iFLsZy.png

在这里我写一个叫做 Entity 的结构体,给他两个整数 x 和 y。

在这里我用的是结构体 struct,你当然也可以使用类,没有关系。我选择结构体的原因是我想让这些 x 和 y 变量是公有的。而通过使用 struct 默认情况下就是公有的。之前有一期是介绍 class 和 struct 的区别的,如果你想要去看的话,可以先去看一下。

我们现在有一个非常简单的基类。并且实例化它,将其值设置为我们想要的值。

如果我想创建这个类的另一个实例,我也可以用第二种方法,然后用初始化器来完成初始化。

然后我们给了 Entity 结构的一个方法 Print。让两个实例分别调用 Print。

运行之后可以看到,结果很清楚,并没有什么问题。

如果我让变量变为静态的话,事情就会有些不一样了。

首先出现问题的地方是第二种初始化方法,x 和 y 变成静态的话,这样的初始化操作会失败,因为 x 和 y 不再是类成员。

我们先修改一下它。(严格意义上说,这样的写法也是不对的,不过作为一个例子还行)

iFLvH5.png

我们有两个不同的实例,至少看起来是这样的。

如果我们运行代码,我们会得到一个错误。

iFL9e8.png

这是因为我们需要在某个地方定义那些静态变量。

我们可以这样操作。

iFLJaZ.png

好了,现在链接器器可以连接到合适的变量了。

然后我们运行代码。

结果是什么?你会看到我们实际上打印了两次 5 和 8,结果有点奇怪是吧。

我们回去看代码,首先我们在第一个实例上的设定了 x,y 等于 2 和 3。第二个为 5 和 8。然而你要记得,当 x 和 y 变成静态时,我们让这两个变量在 Entity 类的所有实例中只有一个实例。这意味着当我改变第二个 Entity 实例的 x 和 y时,它们实际上和第一个完全是一样的,他们指向的是相同的内存。

没错,两个不同的 Entity 实例,他们的 x 和 y 指向同一个地方。这时候你就会明白,我们这样这样引用是没有意义的。其实可以像这样引用它们,有点像他们在这个 Entity 的作用域内。

iFLLkF.png

这就是它们的全部了。

就像我们在名为 Entity 的命名空间中创建了两个变量,它们实际上并不属于类。

从严格意义上说它们可以是私有的,它们仍然是类的一部分,而不是命名空间的一部分。

但是无论出于何种目的,当你创建一个新的类的实例或类似的东西时,他们其实和在命名空间中是一样的。与如何分配无关。

如果我们要正确的重写代码,你可以看到很多代码都没啥意义了,为什么之前我们得的是 5 和 8?因为我们实际上是在修改相同的变量。

那么,这样做的意义是什么?

它有什么用

这当然很有用,当你想要跨类使用变量时,你可以使用一个静态全局变量而不使用全局变量,它是在内部进行链接的。不会在你这整个项目都是全局的。

那你为什么要这么做呢?答案是把他们放在 Entity 中是有意义的。

如果你有一个东西,举个例子,比如你有一条信息。你想要在所有的实例之间的共享数据。这时候将它存储在类中是有意义的,因为它与 Entity 有关。

要组织好代码,那你最好在这个类中创建一个静态变量,而不是一些静态的或全局的东西到处乱放。

静态方法的工作方式与此类似,如果我让这个 Print 方法变成静态,它是会正常工作的。

iFLMBH.png

因为你可以看它指向 x 和 y,它们也是静态变量。

调用方式其实也可以改变了。事实上这才是正确的调用方式,当然你也可以注意到它会打印出相同的东西,——因为我们运行了两次相同的方法嘛。

这个例子中我们甚至不需要使用类实例,因为我们所做的一切都是静态的。然而如果我们决定让 x y 是非静态的,程序就不能运行了。Print 的方法仍然保持 static,但静态方法不能访问非静态变量

有些人可能会对静态的东西不能访问什么非静态的东西感到非常困惑。其实这很好理解。看看这个例子。

我们回到 Entity 实例,恢复我们的代码。

iFLP9Q.png

这样我们实际上对于 Entity 类的每个实例都有一个单独的 x 和 y。仍然将 Print 方法保持为静态。

现在尝试生成代码。会得到一个错误,你可以看到非法引用的非静态成员,因为你不能从静态方法访问他。原因是静态方法没有类实例。

我可能会在以后的系列中详细讲解类是如何运作的。但你要先简单了解接下来的内容:在类中写的每一个方法,每个非静态方法总是获得当前类的一个实例作为参数,这就是类幕后的实际工作方式,在类中你看不到这种东西,它们通过隐藏参数发挥作用。而静态方法不会得到那个隐藏参数。

静态方法与类外部编写方法相同。

如果我在外面写一个方法。你就知道为什么不能访问 x 和 y 了。

iFL1rC.png

很明显,它不知道 x 和 y 是啥。

但是想象你有同样的 Print 方法。但是有一个 Entity 的对象是作为参数传入的。你的代码改成这样就可以了。

iFLQhP.png

刚才写的这个方法本质上是非静态类方法在编译时的真实样子。

如果我们把这个 Entity 实例去掉,这正是我们将 static 关键字添加到类方法时所做的事情。这就是为什么会得到错误,它不知道要访问哪个 Entity 的 x 和 y,因为你没有给它一个 Entity 的引用。

最后的话

我希望我把相关的内容都讲清楚了。下期我们看看如何将许多的 static 知识整合了到我们一直在研究的 log 类中,看看那会变成是什么样子。

你可以先去看一下如何写一个 C++ 类那期。随着系列的进行,我们会继续增加 log 类的内容,并发掘一些我们可以做的新事情,并在学习新概念的同时不断改进它。

好了,记住,static 对于那些静态数据非常有用,这些数据不会在类实例之间发生变化。

本期的内容就是这些,下期再见。

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

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

相关文章

【c#串口通信从小白到大神(5)】如何打开串口

1、新建一个winform程序 这里以visual studio 2019 社区版为例,关于visual studio 2019 社区版的下载链接请点击这里:如何下载安装visual studio 2019 社区版 第1步、打开visual studio 2019 ,出现下图: 第2步、点击“创建新项目”,如下图: 第3步、选择 “Windows 窗…

深眸科技围绕机器视觉技术,加速实现制造行业生产线智能化升级

工业4.0时代,是以智能制造为代表的第四次工业革命时代。随着人工智能的高速发展,机器视觉作为当前制造业质量控制领域的重要技术之一,在各行各业的应用逐渐广泛,其行业市场需求进一步飙升。据GGII预测,预计2025年&…

openEuler实验-使用Shell脚本实现局域网MAC地址收集和FTP服务监控

linux的简单运用 目录 前言 1. 实验目的 2. 实验内容 3. 实验知识点 4. 实验时长 5. 实验环境 实验分析 部署FTP服务器 1)安装FTP服务 2)查看FTP服务 3)启动FTP服务 4)关闭FTP服务 收集MAC地址 1)修改主…

C++17字符流以及C++11文件流以及IO流

getline() 有时候我们希望在最终的字符串中保留输入时的空白符,这时候应该用getline函数来替代原来的>>运算符。( cin 不能输入包含嵌入空格的字符串)。 getline()函数的参数是一个输入流和一个string对象,原型是&#xf…

threejs的使用

threejs介绍: Three.js是一款基于WebGL的JavaScript 3D库,用于创建和渲染3D图形场景。它提供了一个简单易用的接口,让开发者可以通过JavaScript代码创建出高度交互性和可视化的3D场景。Three.js提供了很多可用的3D对象和材质,例如…

C++ -2- 类和对象(上)| 什么是类

​ 文章目录 1.面向过程与面向对象2.类的引入3.类的定义两种定义方式 4.类的访问限定符5.类的作用域6.类的示例化7.类的对象大小计算8.类成员函数的this指针C语言和C的对比(this指针)空指针的问题 C语言和C实现Stack对比 1.面向过程与面向对象 C:面向过程&#xf…

java获取请求ip的方法

在上篇文章中我们介绍了 java获取请求 ip的方法,那么这篇文章我们就来详细讲解下获取请求 ip的方法。获取请求 ip的方法是基于 HTTP协议的,其原理如下: 1、用 web应用程序,将 web服务器端与客户端通过 HTTP协议通信。 2、客户端发…

LNMP架构和论坛搭建以及一键部署

数据流向 一、Nginx服务安装 1、关闭防火墙 [rootking ~]# systemctl stop firewalld [rootking ~]# systemctl disable firewalld [rootking ~]# setenforce 0 2、将所需软件包拖入/opt目录下 3、安装依赖包 yum -y install pcre-devel zlib-devel gcc gcc-c make 4、创建运…

Feign快速入门

文章目录 一、Feign1.1 Feign介绍1.2 Feign的使用步骤1.3 Feign的自定义配置1.3.1 配置方法 1.4 Feign的优化 一、Feign 1.1 Feign介绍 Feign是一个Java HTTP客户端,它使开发人员可以轻松地与RESTful API进行交互。Feign使用注释来描述REST API,它还支持…

Springboot整合Junit5

1 SpringBoot整合Junit (一)junit5 介绍 Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库 作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成。 JUnit 5 JUnit Platfo…

音视频开发十九:SDL线程和事件

SDL事件相关API DL_Event 是SDL库中使用的一个数据结构,用于表示系统中发生的事件。一个事件可以是键盘按键、鼠标移动、游戏手柄移动、窗口事件等。SDL_Event 结构包含有关事件类型、事件发生时间和事件参数的详细信息。 SDL_Event 结构具有以下成员:…

[5 种有效方法] 适用于 Android 的通用解锁图案/密码

在当今世界,保护您的密码对于您的文件和数据的安全至关重要,尤其是在第三方应用程序盛行的情况下。为这些应用程序注册帐户不是问题,就像记住它们一样。但是,如果您不知何故忘记了手机密码,您仍然可以在不丢失宝贵数据…

突破规模化运维瓶颈 SREWorks云原生数智运维平台揭秘

作者: 钟炯恩——阿里云大数据基础工程技术团队运维专家 引言 突破规模化运维瓶颈是诸多IT规模增长的企业及组织当前遇到的比较棘手的问题。面对这些问题,多数人的第一反应是上云。但是上云之后我们会发现,即使云上的架构规模增大&#xf…

如何使用DNS实现融合CDN功能

将托管DNS解决方案与CDN配对可为您的网站提供额外的性能、可靠性和灵活性。 域名系统(DNS)是一种用于计算机、服务或连接到Internet或专用网络的任何资源的分层分布式命名系统,它将各种信息与分配给每个参与实体的域名相关联,它基…

ChatGPT 火了,一大批开源平替也来了

ChatGPT 凭一己之力让全球为 AI 沸腾,引发了科技巨头之间的聊天机器人军备竞赛。 众所周知,ChatGPT 的背后技术是 GPT(Generative Pre-trained Transformer)模型。GPT 是一种基于 Transformer 模型的自然语言处理模型,由 OpenAI 公司开发。它…

【elasticsearch部署】

安装elasticsearch 1.部署单点es1.1.创建网络1.2.加载镜像1.3.运行 2.部署kibana2.1.部署2.2.DevTools 3.安装IK分词器3.1.在线安装ik插件(较慢)3.2.离线安装ik插件(推荐)1)查看数据卷目录2)解压缩分词器安…

前端必备的nginx知识点

nginx学习,看这一篇就够了:下载、安装。使用:正向代理、反向代理、负载均衡。常用命令和配置文件,很全_java冯坚持的博客-CSDN博客 前端必备的nginx知识点 - 掘金 前言: 最近在做一个后台项目 ngixn简介 nginx是一款轻量级&…

【Sql】sql语句练习随记

本文通过最经典的“学生-成绩-课程-教师”表来帮助练习sql语句。 STUDENT表 SNO 学号SNAME 姓名SSEX 性别SBIRTHDAY 生日CLASS 班级 SCORE表 SNO 学号CNO 课程编号DEGREE 分数 COURSE表 CNO 课程编号CNAME 课程名称TNO 教师编号 TEACHER表 TNO 教师编号TNAME 教师姓名TS…

(包教包会)最强分布式锁工具:Redisson

今天来聊聊分布式锁的最强实现:Redisson 从分布式锁到Redisson实现非常详细,适合慢慢咀嚼~ 一. Redisson概述 1.1 什么是Redisson? Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。…

CRMEB开源商城/标准版后台默认admin路径修改、后台目录地址修改

默认admin路径修改 v4.7 版本开始兼容可以修改admin路径,可以根据自己的要求更换后台访问地址; 默认路径不能携带特殊字符、全部都为小写字母 修改后台admin默认路径 标准版本文件位置根目录/config/app.php 开源版本文件位置根目录/crmeb/config/app.p…