P13 C++ 类 | 结构体内部的静态static

目录

01 前言

02 类内部创建静态变量的例子

03 在类的内部创建静态变量的作用

04 最后的话


01 前言

本期我们讨论 static 在一个类或一个结构体中的具体情况。

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

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

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

02 类内部创建静态变量的例子

让我们来看一下例子。

#include <iostream>
using namespace std;
class Dog
{
public:
    int age;
    const char *name;
    void print()
    {
            cout <<name<<": "<<age << endl;
    }
};

int main()
{
    Dog dog;
    dog.age = 10;
    dog.name = "xiaohuan";
    Dog dog2 = {15,"xiaobai"};
    dog.print();
    dog2.print();
    return 0;
}

在这里我写一个叫做 Dog 类,一个整形变量age,一个常量指针name。

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

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

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

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

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

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

我们先修改一下它。

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

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

编译器会告诉我们未定义变量,这是因为我们需要在某个地方定义那些静态变量。

我们可以这样操作。

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

然后我们运行代码。

你会看到我们实际上打印了两次 一样的数据,结果有点奇怪。

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

没错,两个不同的 Dog实例,他们的 age 和 name指向同一个地方。这时候你就会明白,我们这样这样引用是没有意义的。

当然,如果让变量静态化之后,也可以这样初始化

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

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

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

03 在类的内部创建静态变量的作用

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

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

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

举个例子,比如你想创建一个日志报表Log,其中有一条信息。你想要在所有的实例之间的共享数据。这时候将它存储在类中是有意义的,因为它与 Log有关。

要组织好代码,那你最好在这个类中创建一个静态变量,而不是一些静态的或全局的东西到处乱放。静态方法的工作方式与此类似,如果我让这个 Print 方法变成静态,它是会正常工作的。

看上述代码,我们在Log类中创建了一个messas字符串,然后我们在主函数将其初始化,初始化完将messags打印出来,很好,我们说过在类内部定义静态变量,其实所有的实例之间的数据数据是共享的,然后再在类的外部定义一个函数,在函数内将类的messags进行修改,最后在主函数打印出来。

04 最后的话

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

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

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

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

Dog类相关代码

#include <iostream>
using namespace std;
class Dog
{
public:
    static int age;
    static const char *name;
    static void print()
    {
            cout <<name<<": "<<age << endl;
    }
};

static void print(Dog dog)    //也可以这样使用类的静态变量
{
    cout <<dog.name<<": "<<dog.age << endl;
}

int Dog::age;   //定义变量,不然对象并不能找到定义,因为static相当于在类中能认识,但类的范围外并不认识
const char* Dog::name;

class Log
{
    char *messages;
};

int main()
{
    Dog dog;
    dog.age = 10;
    dog.name = "xiaohuan";
    //Dog dog2;
    Dog::age = 12;
    Dog::name = "xiaobiao";
    dog.print();
    //dog2.print();
    return 0;
}

Log 相关代码 

#include <iostream>
using namespace std;
class Log
{
public:
    static string messages;
    static void print()  //如果变量为非静态的话,则需要将类传进出,Log s ,s.messages
    {
        std::cout<< messages<<std::endl;
    }
};

void print()
{
    Log::messages = "this is from nothing funtion message";
}
string Log::messages;

int main()
{
    Log::messages = "this is a test form main";
    Log::print();
    print();
    Log::print();
    return 0;
}

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@ChenPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值