【C++】——类的static成员

举报
YIN_尹 发表于 2023/08/21 18:51:45 2023/08/21
【摘要】 static 成员我们来看这样一个面试题:要求我们实现一个类,并在程序中能够计算出一共创建了多少个类对象。那大家想一下,可以怎么做?直接去数行不行啊? 直接数是不是有可能不靠谱啊,因为有些创造类对象的地方是不是会进行优化,这个我们上面刚刚讲过。那还可以怎么搞呢?大家想一下,要创建一个类对象,有哪些途径,是不是一定是通过构造函数或者拷贝构造搞出来的。 那我们是不是可以考虑利用构造函数和拷贝构造...

static 成员

我们来看这样一个面试题:

要求我们实现一个类,并在程序中能够计算出一共创建了多少个类对象。

那大家想一下,可以怎么做?

直接去数行不行啊? 直接数是不是有可能不靠谱啊,因为有些创造类对象的地方是不是会进行优化,这个我们上面刚刚讲过。

那还可以怎么搞呢?

大家想一下,要创建一个类对象,有哪些途径,是不是一定是通过构造函数或者拷贝构造搞出来的 那我们是不是可以考虑利用构造函数和拷贝构造来计算创建出来的对象个数啊。

class A
{
public:
    A(int a)
    {
        
    }
    A(const A& aa)
    {
    }
};

假设我们现在创建了这样几个对象:

void func(A a)
{}
int main()
{
    A a1;
    A a2(a1);
    func(a1);
    A a3 = 1;
​
    return 0;
}

那我们就可以怎么做:

<font color = black>🆗,定义一个全局变量n,初值为0。 在这里插入图片描述 然后每次调用构造函数或者拷贝构造创建对象时就让n++,那这样最后n的值是不是就是创建的对象的个数啊。

我们来测试一下:

在这里插入图片描述 结果是4,对不对啊。 我们分析一下其实就是4,答案没问题。

但是大家说当前这种方法好吗?

其实是不太好的,为什么? 首先这里我们用了一个全局变量,那首先第一个问题就是它可能会发生命名冲突;其次,全局的话,是不是在哪都能访问它(而C++讲究封装),都可以修改它啊,如果在其它地方不小心++了几次,结果是不是就不准了啊。

那有没有更好一点的方法呢?

那当然是有的。 应该怎么做呢? 🆗,我们把统计个数的这个变量放到类里面,这样它就属于这个类域了,就不会命名冲突了,然后如果不想让它在类外面被访问到,我们可以把它修饰成私有的就行了

但是:

如果直接放到类里面,作为类的一个成员变量: 在这里插入图片描述 那它是不是就属于对象了,但我们要统计程序中创建对象的个数,这样我们每次创建一个对象n就会定义一次,是不是不行啊。 不能让它属于每个对象,是不是应该让它属于整个类啊。

2.1 静态成员变量

怎么做呢?

在它前面加一个static修饰,让它成为静态成员变量。 那这样它就不再属于某个具体对象了,而是存储在静态区,为所有类对象所共享 在这里插入图片描述 但是我们发现加了static之后报错了,为什么? 因为静态成员变量是不能在这里声明的时候给缺省值的。 非静态成员变量才可以给缺省值。 大家可以想一下嘛,缺省值其实是在什么时候用的,在初始化列表用的,用来初始化对象的成员变量的,而静态成员变量我们说了,它是属于整个类的,被所有对象所共享。

类里面的是声明,那静态成员变量的初始化应该在哪?

🆗,规定静态成员变量的初始化(定义的时候赋初值)一定要在类外,定义时不添加static关键字,类中只是声明。 在这里插入图片描述

但是现在又有一个问题:

在这里插入图片描述 <font color = black>我们把它搞成私有的,在外面就不能访问了。 当然如果不加private修饰就可以了: 在这里插入图片描述 另外呢,这里除了指定类域来访问静态成员变量,还可以通过对象去访问: 在这里插入图片描述 因为它属于整个类,并且被所有对象共享。 还可以这样: 在这里插入图片描述 这个问题我们之前是不是说过啊,不能看到->或者.就认为一定存在解引用,还是要根据具体情况进行分析。 当然如果是私有的情况下,这样写是不是统统不行啊: 在这里插入图片描述 那我们就可以写一个Get方法: 在这里插入图片描述 在这里插入图片描述 成员函数是需要通过对象去调用的 这样就可以了。

那如果我们的程序是这样的呢?

在这里插入图片描述 在main函数里面我们根本没有创建对象,那我们还怎么调用Getn函数呢? 难道我们专门在main函数里创建一个对象去调用Getn,然后再把结果减1: 在这里插入图片描述 因为main函数里的对象是我们为了调用函数而创建的对象,所以最后要减去。

2.1 静态成员函数

那有没有什么办法可以不通过对象就能调用到Getn函数呢?

那我们就可以把Getn函数搞成静态成员函数,也是在前面加一个static关键字就行了。 在这里插入图片描述 但是静态成员函数有一个特性:静态成员函数没有隐藏的this指针,不能访问任何非静态成员。 因为非静态成员是属于对象的,都是通过this指针去访问的,而静态成员函数是没有this指针的。 在这里插入图片描述 那它没有this指针,就可以不通过对象调用了,所以现在我们通过指定类域也可以调用到静态的Getn函数。 在这里插入图片描述 当然你还通过对象调用也还是可以的。

那我们现在在加一个东西:

在这里插入图片描述 大家觉得现在结果会多几个对象: 在这里插入图片描述 🆗,13个,是不是比之前多了10个啊,因为我们又多定义了一个大小为10 的类对象数组。

2.3 练习

那接下来我们来做个题: link 在这里插入图片描述 在这里插入图片描述

这道题呢就是让我们求一个1到n的和,但是要求了一大堆,不让用这,不让用那的。 🆗,那不用就不用呗,其实借助我们刚才学的知识,就可以很巧妙的去解这道题。

怎么做呢?

在这里插入图片描述 我们自己呢定义这样一个类,两个静态成员变量_i_sum,分别初始化为0,1。 然后我们调用一次构造函数,就让_sum+=_i,然后_i++,这样第一次+1,第二次+2... 那现在我们要求1+2+3...+n的和,怎么办? 是不是是需要调用n次构造函数,所以,我们直接定义一个大小为n的类对象数组就行了。

class Sum{
public:
    Sum()
    {
        _sum +=_i;
        ++_i;
    }
    static int GetSum()
    {
        return _sum;
    }
private:
    static int _i;
    static int _sum;
};
int Sum::_i=1;
int Sum::_sum=0;
​
class Solution {
public:
    int Sum_Solution(int n) {
        Sum arr[n];//C99支持变长数组,可以用变量指定数组大小,但不能初始化。
        return Sum::GetSum();
    }
};

在这里插入图片描述

这样就行了。

2.4 总结

那最后我们来总结一下:

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。

特性:

  1. <font color = red>静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区

  2. <font color = red>静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明,静态成员变量一定要在类外进行初始化

  3. <font color = red>类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问

  4. <font color = red>静态成员函数没有隐藏的this指针,不能访问任何非静态成员

  5. <font color = red>静态成员也是类的成员,受public、protected、private 访问限定符的限制

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。