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

您所在的位置:网站首页 静态结构体 C++类和结构体中的静态(static)

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

2024-07-17 15:10| 来源: 网络整理| 查看: 265

上一篇:C++中的静态static

下一篇:C++中的局部静态(static)

1. 概述

本篇主要讨论在类和结构体中的静态static。上一篇我们讨论了C++中的static关键字以及他在类和结构体之外的意义。当static在一个类或者结构体中,它的意义是什么。

在几乎所有的面向对象的语言中,静态在一个类中意味着特定的东西,如果我们将它和变量一起使用,这就意味着在类的所有实例中,这个变量只有一个实例,如果我创建一个名为Entity的类,我不断创建Entity实例,我仍然只会得到那个变量的一个版本。也就是说,如果某个实例改变了这个静态变量,它会在所有实例中反映这个变化,这是因为这里只有一个变量,尽管我已经创建了一大堆的类的实例。

正因如此,通过类实例来引用静态变量是没有意义的。因为这就像类的全局实例,静态方法也是一样。静态方法的调用无需通过类实例,且在静态方法内部,无法引用到类实例的代码,因为静态方法不能引用到类的实例。

2. 案例 1. 项目准备

准备一个简单的项目,项目中有一个Main.cpp文件,内容如下。

image.png

2. 开始案例

在main.cpp文件中,我们写一个Entity的结构体,如下

image.png

这里用的结构体,其实也可以使用类,这都没关系。我在这里选择结构体的原因是我想让这些x和y变量是public。通过使用struct,这些变量默认是public。有关struct和class的相关内容,有在C++类和结构体对比中讲过。

现在,我们有了一个非常简单的Entity,接下来我们来实例化它,并将Entity中的值设置为我们想要的值,如下

image.png

如果我还想创建这个类的另一个实例,我们也可以这样做。这次我们用初始化器来做初始化Entity e1 = {5, 8};

image.png

然后我们给Entity结构体一个函数print,打印消息到控制台。如下

image.png

然后,我们在main函数中调用

image.png

F5运行程序

image.png

可以看到,我们得到2, 3和5, 8。

然而,如果结构体中的变量是静态的,打印的结果就不是这样了。

3. 类中的静态变量

下面将Entity结构体中的x,y变量变成静态的,只需在变量前面加上static修饰。如下

image.png

可以看到main函数中,通过初始化方式实例化的Entity对象出现了错误提示。

image.png

这里会初始化失败,这是因为x和y不再是类成员。所以我们换种写法。

image.png

严格意义上,这写的也不对,然而这只是做个例子无妨。

所以可以看到我们引用了两个不同的实例,至少看起来是这样。

如果我们F5运行代码。

image.png

可以看到,我们会得到无法解析的外部命令错误。因为我们实际上需要在某个地方定义那些静态变量。

4. 定义静态变量

我们可以这样做,在结构体外,写上int Entity::x;,这里先写作用域Entity,再写变量名x。同样,写上int Entity::y;。

image.png

这样x, y被定义了,链接器可以链接到合适的变量。

然后我们F5运行程序

image.png

可以看到两次得到的都是5,8。

image.png

这有点奇怪,可以看到代码,首先我们在第一个实例上设定了x等于2, y等于3,然后在第二个实例上设定了x等于5,y等于8,然而打印出来的却都是5, 8。

记住,这些x和y变量,当我们让它们静态时,那就是我们让这两个变量在Entity类的所有实例中只有一个实例。这意味着当我改变第二个实例的x和y时,它们实际上和第一个完全一样,它们指向的是相同的内存。两个不同的Entity实例,它们的x和y,指向同一个地方,它们指向相同的x和y。

我们e.x或e.y,e1.x或e1.y这样引用是没什么意义的。

5. 引用静态变量

我们可以像这样引用它们,Entity::x或Entity::y,

image.png

就像它们在这个Entity作用域内,这就是它们的全部。这就像我们在名为Entity的命名空间中创建了两个变量,它们实际上并不属于类。当然,从这个意义上讲,它们可以是private的,也可以是public的,它们仍然是类的一部分,而不是命名空间。但无论出于何种目的,当你创建一个新的类的实例或类似的东西时,它们其实和在命名空间中一样,它们与任何分配无关。

如果我们要正确的重写代码

image.png

可以看到,为什么之前我们得到的都是5,8。因为我们实际上是在修改相同的变量。当我们想要跨类使用变量时,这是很有用的。当然,我们也可以通过创建一个全局变量,或者不使用全局变量,而是使用一个在内部进行链接的静态全局变量,这个静态全局变量不会在整个项目中是全局的,这样做也会有同样的效果。那我们为什么还要在类中使用静态呢?答案是,把它们放在类中是有意义的,如果你有东西,比如一条消息,你想要在所有的Entity实例之间共享数据,或者将它实际存储在Entity类中是有意义的,因为它与Entity相关。要组织好代码,我们最好在这个类中创建一个静态变量,而不是使用一些静态全局或全局的东西到处乱放。

6. 静态方法

静态方法的工作方式与静态变量类似。在方法前面加上static修饰

如果我们让print方法变成静态,它会正常工作,因为可以看到,它指向的x和y,它们也是静态的。

Snipaste_2024-01-02_14-28-14.png

7. 静态方法调用

所以,我们的调用方式可以这样调用

image.png

这才是正确的调用方式。当然,可以看到,它会打印出同样的东西,因为我们运行了两次相同的方法Entity::Print();。

在这个例子中,我们甚至都可以不需要类实例,因为我们所做的一切都是静态的。如下。

image.png

8. 静态方法不能方位非静态变量

然而,如果我们决定让x和y是非静态的,事情就变了。print方法仍然保持static静态,但静态方法不能访问非静态变量。

有些人可能会对静态的东西能访问什么非静态的东西感到困惑,其实它真的一点也不让人困惑。下面来看看,我们将print函数保持静态,将x,y恢复成非静态。如下

image.png

我们尝试编译代码 ctrl + F7

image.png

可以看到,我们会得到一个错误,对非静态成员“Entity::x”的非法引用,因为我们不能从静态方法访问非静态变量,原因是静态方法没有类实例。本质上,我们在类中写的每一个方法,每个非静态方法总是获得当前类的一个实例作为参数,这就是类在幕后的实际工作方式。在类中你看不到这种东西,它们通过隐藏参数发挥作用,静态方法不会得到那个隐藏参数,静态方法与类外部编写方法相同。如果我们在外面写一个print方法,你就会知道为什么不能访问x和y了。因为pirnt函数并不知道x,y它们是什么。

image.png

想象一下,我们有同样的print方法,但是有一个Entity对象,是作为参数传入的。代码改成如下这样

image.png

这样就可以了。我们刚才写的这个print方法,本质上是非静态类方法在编译时的真实样子。

如果我们将static关键字添加在类方法时,所做的便是没有Entity参数的

image.png

这便是为什么编译会得到对非静态成员“Entity::x”的非法引用的错误。因为静态方法不知道我们想要访问哪个Entity的x和y,因为我们没有给它一个Entity的引用。所有的这些情况,我希望都讲清楚了,后续我们会看看如何将学到的static知识,整合到我们一直研究的Log类中,看看那会是什么样子,关于创建log类,并后续不断升级它的内容,见如何写一个C++类。随着这个系列的进行,我们将继续增加Log类的内容,并找出一些我们可以做的新事情,并在学习新概念的同时不断改进它。

static对于那些静态数据非常有用,这些数据不会在类实例之间发生变化,但实际上我们想在类中使用它们。

上一篇:C++中的静态static

下一篇:C++中的局部静态(static)



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3