当前位置: 首页 > news >正文

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

目录

1.static成员变量

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

设计思路

代码示例

版本1

版本2

static成员

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

特点2.静态成员变量必须在类外初始化,定义时不添加static关键字,类中只是声明

特点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.静态成员变量必须在类外初始化,定义时不添加static关键字,类中只是声明

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

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

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

正确写法:

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

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

特点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;
}

运行结果:

http://www.dtcms.com/a/122904.html

相关文章:

  • redis(2)-mysql-锁
  • 经典算法 最近点对问题
  • 猜猜乐游戏(python)
  • Trae AI 保姆级教程:从安装到调试全流程指南
  • FastAdmin和thinkPHP学习文档
  • 国标GB28181协议EasyCVR视频融合平台:5G时代远程监控赋能通信基站安全管理
  • 文字识别 (OCR) 工具
  • js 拷贝-包含处理循环引用问题
  • c++和python复制java文件到指定目录
  • AQS机制详解与总结
  • java方法07:加减乘除计算器
  • rkmpp 解码 精简mpi_dec_test.c例程
  • LeetCode 热题 100 题解记录
  • Docker Hello World
  • 计算机网络 实验三:子网划分与组网
  • GaussDB性能调优:从根因分析到优化落地
  • 10. git switch
  • Java MCP SDK 开发笔记(一)
  • 深度学习疑问--Transformer【3】:transformer的encoder和decoder分别有什么用?encoder是可以单独使用的吗
  • WHAT - React 进一步学习推荐
  • Electron 应用太重?试试 PakePlus 轻装上阵
  • LVM 扩容详解
  • 0 std::process::Command 介绍
  • 中小型网络拓扑图静态路由方式
  • 监测fastapi服务并自动拉起(不依靠dockerfile)
  • 低代码开发平台:飞帆画 echarts 仪表盘
  • Redis最佳实践——用户会话管理详解
  • 金陵幻境录——六朝古都的科技诗篇-南京
  • go游戏后端开发29:实现游戏内聊天
  • 用 HTML 网页来管理 Markdown 标题序号