类的静态成员与静态函数成员

77 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情

1、问题背景

比如说我们有一个平面直角坐标系,然后创建一个Point类,里面有设有(x,y)横纵坐标的成员变量,和一个totalPoint的变量去描述平面直角坐标系上点的个数。这时我们会发现每一个实例化的对象都有(x,y)横纵坐标,所有实例化的对象共用一个totalPoint。这就意味着totalPoint不能像(x,y)横纵坐标一样是普通的成员变量,如果把totalPOint设置成与(x,y)横纵一样的普通成员变量,那么每实例化一个对象都会产生一个totalPoint的副本,就会在成冗余。如果把totalPoint设置为全部变量,则又失去了一定隐蔽性,无法实现数据的隐藏。所以就产生的静态成员来解决这个问题。

2、静态成员变量

#include<iostream>
using namespace std;
class Point
{
public:
	//构造函数,每构造一个坐标点就countP加一
	Point(int xx,int yy=0)
	{
		this->X = xx;
		this->Y = yy;
		totalPoint++;
	}
	//析构函数,每析构一个坐标点就countP减一
	~Point()
	{
		totalPoint--;
	}
	//拷贝构造函数
	Point(Point &p)
	{
		this->X = p.X; this->Y = p.Y; totalPoint++;
	}
	int GetX() { return X; }
	int GetY() { return Y; }
	int GetCountP() {return totalPoint;}
private:
	int X, Y;
	static int totalPoint;//点的数量
	//此处不可赋值,隐蔽性好,可共享,没有副本不冗余。
};
int Point::totalPoint = 0;//在文件作用域内初始化
int main()
{
	Point A(4, 5);
	cout << "Point A," << A.GetX() << "," << A.GetY() << endl;
	A.GetCountP();
	Point B(A);
	cout << "Point B," << B.GetX() << "," << B.GetY() << endl;
	cout << "totalPoint:" << A.GetCountP() << endl;
	cout << "totalPoint:" << B.GetCountP() << endl;
	//countP是A、B共享的成员变量。
}

上述案例中Point类中,把totalPoint设置为静态成员变量,创建A点时totalPoint=1,创建B点时totalPoint=2;

image.png

3、静态成员函数

上面的代码也有一个小bug,我们获取totalPoint需要通过调用成员函数GetCountP(),而想要调用GetCountP()有需要先实例化一个对象,这样一来totalPoint最小等1,但是平面直角坐标系上可以没有点,totalPoint可以为0。那么怎么修复这个bug呢,答案是静态成员函数,和静态成员变量的思想是一样的,静态成员变量是不属于某一个实例化的对象的,而是属于这个类;同理,静态成员函数也不是属于某一个实例化的对象的,而是属于这个类的。

static int GetCountP() {return totalPoint;}//依法很简单,加个static就🆗了。

image.png

4、使用静态成员和静态成员函数的注意事项

1、不能使用类名来调用类的非静态成员函数

void fun()
{
    Point ::GetCountP();//正确,GetCountP()是静态成员函数
    Point ::GetX();//错误,GetX()是非静态成员函数
}

2、通过类实例化的对象可以调用静态成员函数和非静态成员函数

void fun2()
{
    Ponit A(1,2);
    A.GetCountP();//正确
    A.GetX();//正确
}

3、静态成员函数不能引用非静态成员。因为静态成员函数属于整个类,在类实例化之前就已经分配好空间了,而类的非静态成员必须在类实例化之后才有内存空间。

4、类的非静态成员函数可以调用静态成员函数,但反之不能。

5、类的静态成员函数必须先初始化在使用

5、实验验证

image.png 一个类中啥也没有,它所占字节大小为1。

image.png 加了一个非静态成员变量(int)以后,所占字节大小为4。

image.png 再加一个静态成员变量(int),结果还是4。

做个减法,如果只有静态成员变量 (int),结果应该为1:

image.png 猜想正确。