C++ 类中的静态成员变量和静态函数

发布于:2022-12-24 ⋅ 阅读:(199) ⋅ 点赞:(0)

目录

一、什么是静态属性?

二、静态成员变量的特点与优势

1.静态成员变量特点

2.静态成员变量优势

三、静态方法


一、什么是静态属性?

  在类型设计中,用关键字static修饰的数据成员为静态数据成员,由该类型所实例化的所有对象,共享系统为静态成员分配的一个存储空间,这个存储空间是程序执行main函数之前分配的。在实例化对象时不再为静态成员分配空间。也就是说静态成员数据不在对象空间中。

二、静态成员变量的特点与优势

1.静态成员变量特点

(1)使用静态成员变量的主要目的是信息共享

设计一个圆类作为示例,代码如下:

#include<iostream>

using namespace std;

class Circle
{
private:
	double pi;
	double radius;//圆的半径
public:
	Circle(double r = 0.0):pi(3.14),radius(r){}
	~Circle(){}

	double area()const
	{
		return pi * radius * radius;
	}
};

int main()
{
	Circle cir(12.23);
	cir.area();
	size_t sz = sizeof(cir);
	return 0;
}

 若想让圆类中所有对象都能使用这个pi值,可以将pi设计成静态数据成员:

class Circle
{
private:
	static const double pi;
	double radius;//圆的半径
public:
	//Circle(double r = 0.0):pi(3.14),radius(r){}//error
	Circle(double r =0.0):radius(r){}
	~Circle(){}

	double area()const
	{
		return pi * radius * radius;
	}
};
const double Circle::pi = 3.14;

(注:大家可以发现,如果在构造函数初始化列表中定义静态数据成员会报错,这是因为静态数据成员为所有对象共有,在类内定义则每实例化一个对象都要定义一次静态成员变量 ,重复定义了。所以静态数据成员要在类外初始化。)

(2).静态成员变量先于任何对象的存在而存在。静态数据成员属于整个类型。

(3).静态数据成员在使用时,可以通过类型名直接访问,也可以通过类的对象访问(前提是可访问符为public),格式:类名::静态成员变量名  或 对象.静态成员变量名

(4).当在类的外部定义静态成员时,不能重复 static 关键字,该关键字只出现在类内部的声明语句。

(5)使用静态成员变量可以记录由同一类建立的对象的数量

设计一个猫咪类,代码示例:

class Cat
{
private:
	static int num;
private:
	string _owner;//猫主名
	string _name;//猫名
public:
	Cat(const string& own, const string& name) :_owner(own), _name(name)
	{
		num += 1;
		cout << "Create Cat num:"<< num << endl;
	}
	~Cat()
	{
		num -= 1;
		cout << "Destory Cat num:" << num << endl;
	}

};
 int Cat::num = 0;

(6)在类的成员函数中使用静态数据成员,静态数据成员前没有this指针修饰。

还用上述猫咪类型举例,在猫咪类型中加入print()方法:

class Cat
{
private:
	static int num;
private:
	string _owner;
	string _name;
public:
	Cat(const string& own, const string& name) :_owner(own), _name(name)
	{
		num += 1;
		cout << "Create Cat:" << endl;
	}
	~Cat()
	{
		num -= 1;
		cout << "Destory Cat:" << endl;
	}
	void print()const
	{
		cout << "Owner: " << _owner << "Name: " << _name << endl;
		num += 1;
	}
};
 int Cat::num = 0;

我们发现静态数据成员num在const修饰的print()方法中可以实现+=操作,说明其没有被const限制,而const本质上修饰的是this指针,也就是说明了静态数据成员前没有this指针。

 (7)静态属性的类型是int、char、short,并且前有const修饰时,可以在类内进行初始化。

class Bar
{
private:
	static const int nameSize = 20;
	//static const char namesize[nameSize] = "Xiao wang Bar";//error
};

(8)静态数据成员的类型可以是其所属类,而非static数据成员只能被声明为该类的指针。

代码示例:

class Bar
{
private:
    int a;
	static Bar sm_bar;//ok
private:
	Bar m_bar;//error
	Bar* pr;//ok
};

只有在定义对象时,才会为对象的数据成员分配内存空间,只声明了类而没有定义对象,类的一般数据成员是不占空间的,而上面提到类的静态成员是系统提前单独为其分配好了内存,使用Bar定义对象时,首先需要知道该类型所需要的空间,所以在定义一个Bar对象sm_bar时, 类型所需要的空间只需要计算a所需要的空间即可,是一个可计算的值。

直接定义Bar对象m_bar时,可以认为编译器需要计算int+Bar的大小,但无法确定Bar类型大小,所以报错,非static数据成员只能被声明为该类的指针。

2.静态成员变量优势

同全局变量相比,使用静态成员有两个优势:

(1)静态数据成员没有进入程序全局名字空间,因此不会存在与程序中其他全局名字冲突的可能

(2)可以实现信息隐藏,静态数据成员可以是private成员,而全局变量不能。

三、静态方法

函数成员说明为静态,将与该类不同对象无关,与静态数据成员不同的是,为了方便使用,静态函数成员多为公有。

普通成员函数在参数传递时编译器会隐藏地传递一个this指针,通过this指针来确定调用类产生的哪个对象,而静态函数没有this指针,不能通过静态函数访问普通变量,代码示例:

#include<iostream>
using namespace std;
class Object
{
private:
	static int num;
	int value;
public:
	Object(int val = 0) :value(val) {}
	~Object() {}
	void print()
	{
		cout << "value: " << value << "num: " << num << endl;
	}
	static void show() {
		cout << "value: " << value << "num: " << num << endl;//error,报错
	}
	static void fun(Object& obj)//不能加const,不能定义成常方法
	{
		cout << obj.value << " " << num << endl;
	}
};
int Object::num = 0;

show()是静态成员函数,没有this指针, 不能确定访问哪个对象中的value,所以会报错。并且静态函数成员不能定义成常方法。

四、继承与静态成员

静态成员只有一个,所有对象共享,包括基类和派生类对象。

例:设计一个Person类作为基类,派生出Student学生类和职工Employee类,代码如下

#include<iostream>
using namespace std;
class Person
{
protected:
	static int num;
public:
	Person(){}
	~Person(){}
};
int Person::num = 0;

class Student:public Person
{
public:
	Student() { cout << "Create Student: " << (num += 1) << endl; }
	~Student() { cout << "Destory Student: " << (num -= 1) << endl; }
};

class Employee:public Person
{
public:
	Employee() { cout << "Create Employee: " << (num += 1) << endl; }
	~Employee() { cout << "Destory Employee: " << (num -= 1) << endl; }
};

int main()
{
	Student s1, s2, s3;
	Employee e1, e2;
	return 0;
}

运行结果:

Person基类中设计了静态成员num,在基类外初始化,整个继承体系中只有一个静态成员num,无论派生出多少个子类,都只存在一个num静态成员实例。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到