CD25.【C++ Dev】类和对象(16) static成员(上)

目录

1.static成员变量

问题:实现一个类,计算程序中创建出了多少个类对象

设计思路

代码示例

版本1

版本2

static成员

特点1.static成员为静态成员,为所有类对象所共享(在某种程度上可以理解为全局的,用类去封装"全局变量"),存放在静态区,则不属于某个具体的对象,不能通过初始化列表来初始化

特点2.静态成员变量必须在类外初始化(const修饰的size_t类型除外),定义时不添加static关键字,类中只是声明

如果用const修饰类型为整数类型或枚举类型的静态成员变量(建议不要单独记这个特例,使用通用的语法)

特点3:类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 

练习:求下面代码的打印结果

分析

特点4:静态对象只会定义一次

特点5:静态成员也是类的成员,受public、protected、private 访问限定符的限制

2.static成员函数

特点6:静态成员函数没有this指针,只要指定类域且静态成员变量在public里面就可以访问

3.静态成员函数的理解误区


1.static成员变量

问题:实现一个类,计算程序中创建出了多少个类对象

设计思路

使用一个成员变量count实时记录创建出了多少个类对象

调用构造函数:对象个数+1

调用析构函数:对象个数-1

如果某个函数需要使用自定义类型的拷贝,调用拷贝构造函数,对象个数+1

显示一共创建出了多少个对象:GetCount()成员函数返回count的值

代码示例

版本1
class Myclass
{
public:
	Myclass() 
	{
		count++; 
	}
	Myclass(const Myclass&)
	{
		count++;
	}
	~Myclass() 
    {
		count--; 
	}
	int GetCount() 
	{
		return count; 
	}

private:
	int count=0;
};

但这样做会有问题: count是普通的成员变量,和其对应的对象绑定的,则count的结果只能是0或者1,即创建多少个对象就有多少个count,违背了题目的意思,题目的意思是用一个count来统计创建了多少个类对象

 不建议使用全局变量,因为任何地方都可以随意改变,而且某些情况下会出错,例如:

Myclass function(const Myclass myobj)
{
    static Myclass myobj;
    count++;
}

多次调用function函数,myobj是静态对象,只会初始化一次,但是每调用一次function函数,count都会++,导致错误的结果

这里要引入static成员,封装能完美解决问题

版本2
static成员

特点1.static成员为静态成员,所有类对象所共享(在某种程度上可以理解为全局的,去封装"全局变量"),存放在静态区,则不属于某个具体的对象,不能通过初始化列表来初始化

特点2.静态成员变量必须在类外初始化(const修饰的size_t类型除外),定义时不添加static关键字,类中只是声明

像下面这样写就是错误的:

(静态成员变量无初始化列表,不能加缺省值)

 (静态成员变量无初始化列表)

正确写法:

在类外定义(也仅仅是定义)可以摆脱私有的限制

注:静态成员变量在定义可以摆脱私有,但访问上不能摆脱私有

如果用const修饰类型为整数类型或枚举类型的静态成员变量(建议不要单独记这个特例,使用通用的语法)

既可以在类中定义:

class Myclass
{
public:
	//......
private:
	const static int count = 0;
};

也可以在类中声明,在类外定义:

class Myclass
{
public:
	//......
private:
	const static int count;
};
const int Myclass::count = 0;

如果是其他类型用const修饰会报错:

特点3:类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 

正确代码:

class Myclass
{
public:
	Myclass() 
	{
		count++; 
	}
	Myclass(const Myclass&)
	{
		count++;
	}
	~Myclass() 
	{
		count--; 
	}
	static int GetCount()//静态成员函数
	{
		return count; 
	}
private:
	static int count;
};
int Myclass::count = 0;

测试以下代码:

int main()
{
	Myclass myobj1;
	cout << myobj1.GetCount() << endl;//对象.静态成员
	Myclass myobj2;
	cout << myobj2.GetCount() << endl;
	return 0;
}

或者也可以这样写:

int main()
{
	Myclass myobj1;
	cout << Myclass::GetCount() << endl;//类名::静态成员
	Myclass myobj2;
	cout << Myclass::GetCount() << endl;
	return 0;
}

count在正常变动:

练习:求下面代码的打印结果

Myclass function(const Myclass myobj)
{
	cout << Myclass::GetCount() << endl;
	return myobj;
}

Myclass global_obj;
int main()
{
	cout << Myclass::GetCount() << endl;
	{
		static Myclass myobj0;
		Myclass myobj1;
		cout << Myclass::GetCount() << endl;
	}
	cout << Myclass::GetCount() << endl;
	Myclass myobj2;
	cout << Myclass::GetCount() << endl;
	function(myobj2);
	cout << Myclass::GetCount() << endl;
	return 0;
}
分析

第一次打印:创建了全局对象global_obj,打印结果为1(说明static对象myobj0不会在全局对象前初始化)

第二次打印:创建了静态对象myobj0和局部对象myobj1(),打印结果为3,

第三次打印:myobj1被销毁,myobj0和global_obj都存储在静态区,不受{ }管控,因此打印结果为2

第四次打印:创建了myobj2对象,打印结果为3

第五次打印:调用function(myobj2),由于function接收的参数为const Myclass myobj,需要调用拷贝构造函数,对象+1,count==4,打印结果为4

由于function返回的是对象,因此会再次调用拷贝构造函数创建临时对象,count会短暂变为5

函数结束时,程序会调用两次析构函数,function产生的临时对象和myobj都被销毁,count变回3

第六次打印:打印结果为3

特点4:静态对象只会定义一次

例如以下代码:

Myclass function()
{
	static Myclass myobj;
	return myobj;
}

int main()
{
	function();
	cout << Myclass::GetCount() << endl;
	function();
	cout << Myclass::GetCount() << endl;
	return 0;
}

分析:虽然调用两次function函数,但是myobj只会初始化一次,因此打印结果都是1

特点5:静态成员也是类的成员,受public、protected、private 访问限定符的限制

2.static成员函数

上方代码的Myclass类中有这样一个函数:

static int GetCount()//返回静态类型
{
	return count; 
}

和普通函数不一样的是:GetCount函数的返回类型是static int,则称GetCount是静态成员函数

特点6:静态成员函数没有this指针,只要指定类域且静态成员变量在public里面就可以访问

一般情况下, 静态成员函数和静态成员变量配套出现,例如GetCount()和count静态成员变量

注意:没有this指针就要注意对象的成员变量是不可访问的!

例如以下错误代码:

class Myclass
{
public:
	static int GetCount()
	{
		static int ret=val1;
		return ret;
	}
private:
	int val1=1;
};

错因:静态成员函数中使用非静态成员变量val1,非静态成员变量需要通过对象实例来访问,但静态成员函数没有this指针,因此无法访问到val1

3.静态成员函数的理解误区

之前在CD19.【C++ Dev】类和对象(10) 日期类对象的成员函数(日期+天数)文章中写符取得月份天数的函数

class Date
{
public:
	static int GetMonthDay(int year, int month);
    //省略其他成员函数
private:
	int _year;
	int _month;
	int _day;
};

可以改成静态成员函数,如下:

//int前不要加static!
int Date::GetMonthDay(int year,int month)
{
	static int day[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//默认2月是28天,之后单独判断
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}
	return day[month];
}

注意:在写GetMonthDay函数的定义时,返回类型不要写成static int!!!类的声明中加了static只是表明是类的一个静态成员函数,和返回值没有任何关系 

可以通过如下两种方式调用该函数:

方式1:类名::

#include "Date.h"
int main()
{
	cout << Date::GetMonthDay(2025, 4) << endl;//类名::GetMonthDay(2025, 4)
	return 0;
}

运行结果:

方式2:对象.

#include "Date.h"
int main()
{
	Date d;
	cout << d.GetMonthDay(2025, 4) << endl;//对象.GetMonthDay(2025, 4)
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

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

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

打赏作者

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

抵扣说明:

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

余额充值