【C++】 类练习---封装链表、人物移动

news2024/12/23 22:27:36

目录

前言

正文

结构体和类的区别

练习1:封装链表

用类封装链表的注意事项

定义一个链表的节点结构

链表类代码

主函数

运行结果

练习2:人物移动

说明 

头文件以及宏

人物类

主函数

运行结果

结语


前言

在学完了【C++】 类基础汇总(类封装,构造、析构函数...)后,我们明白了类的特性以及使用方法,那么就需要用一些实例来巩固一下知识点,所以这篇文章就教你如何用类来封装链表和用类来写一个人物移动的小项目。


正文

结构体和类的区别

C++中的结构体和类很像,可以有构造-析构,也有访问修饰符,继承、多态等。区别有两点:

  1. 类成员属性:方法默认是私有的(private),而结构体默认是公有的(public)。
  2. 当从基类、结构体中继承时,类的默认继承方式是私有的(private),而结构体是公有的(public)。

此外在使用习惯上看也略有差别:一般情况,使用类来描述功能实现,而结构体通常只是纯粹的表示数据。比如链表有复杂的数据、很多的方法一般定义成类,而节点只是描述了持有数据的类型和指向下一个节点的指针,一般被定义为结构体。

练习1:封装链表

用类封装链表的注意事项

在使用类封装链表时,需要注意以下几点:

  1. 将链表的节点定义为类中的一个私有内部类,这个内部类应该至少包含两个成员变量:当前节点的值和指向下一个节点的指针。

  2. 类中应该包含头节点和尾节点的指针。头节点是第一个有效节点之前的虚拟节点,尾节点是最后一个有效节点。

  3. 需要实现一些基本的方法,如增加节点、删除节点、查找节点、获取链表长度、判断链表是否为空等。这些方法应该被定义为公有成员函数,以方便外部调用。

  4. 在进行插入或删除操作时,需要注意更新头节点和尾节点的指针。如果链表为空,则插入第一个节点时应同时将头节点和尾节点指向新插入的节点。

  5. 要防止内存泄漏问题,需要在析构函数中对链表中的所有节点进行释放。

定义一个链表的节点结构

struct Node {
	int val;
	Node* pNext;
	Node(int v) {//构造函数初始化
		val = v;
		pNext = nullptr;
	}
};

链表类代码

class CList {
public:
	Node* m_pHead;
	Node* m_pEnd;
	int m_nLen;

public:
	CList() {
		m_pHead = m_pHead = nullptr;
		m_nLen = 0;
	}
	~CList() {
		Node* pNode = nullptr;
		while (m_pHead) { //如果链表不为空,循环
			pNode = m_pHead;  //标记头

			m_pHead = m_pHead->pNext; //头向后移动
			delete pNode; //删除标记的
		}
		Node* m_pHead = nullptr;
		Node* m_pEnd = nullptr;
		int m_nLen = 0;
	}

	void PushBack(int v) {
		Node* pNode = new Node(v);
		if (m_pHead) { //非空链表
			m_pEnd->pNext = pNode;
			m_pEnd = pNode;
		}
		else {//空链表
			m_pHead = pNode;
		}
		m_pEnd = pNode;
		m_nLen++;
	}

	void PopFront() {
		if (m_pHead) {
			Node* pNode = m_pHead;  //标记头,也是将来要删除的
			if (m_pHead == m_pEnd) {  //1个节点
				m_pHead = m_pEnd = nullptr;
			}
			else {  //多个节点
				m_pHead = m_pHead->pNext;//向后移动
			}
			delete pNode; //删除标记的
			pNode = nullptr;
			m_nLen--;
		}
	}

	void ShowList() {
		Node* pNode = m_pHead;
		while (pNode) {
			cout << pNode->val << "  ";
			pNode = pNode->pNext;//向后移动
		}
		cout << endl;
	}

	int GetLength() {
		return m_nLen;
	}

};

主函数

int main()
{
	CList lst;
	lst.PushBack(1);
	lst.PushBack(2);
	lst.PushBack(3);
	lst.PushBack(4);

	cout << lst.GetLength() << endl;

	lst.ShowList();

	lst.PopFront();
	lst.PopFront();

	cout << lst.GetLength() << endl;
	lst.ShowList();

	return 0;
}

运行结果

练习2:人物移动

说明 

用类封装一下人物,其中类成员属性包含人物的图片、坐标和方向;类成员函数包含人物展示,人物移动和运行函数。

头文件以及宏

#include<iostream>
using namespace std;
#include<easyx.h>
#include<conio.h>

#define DIRECT_UP     72
#define DIRECT_DOWN   80
#define DIRECT_LEFT   75
#define DIRECT_RIGHT  77

#define MOVE_STEP  4

#define KEY_ESC 27

人物类

class CPeople {
public:
	IMAGE m_imgUp;     //图片
	IMAGE m_imgDown;
	IMAGE m_imgLeft;
	IMAGE m_imgRight;

	int m_x;    //坐标
	int m_y;


	int m_direct;    //方向
public:
	CPeople() {
		//约定:窗口大小 600*600
		//创建指定大小的窗口
		::initgraph(600, 600);

		//设定窗口的背景色,为白色
		::setbkcolor(RGB(255,255,255));
		::cleardevice();//使窗口背景色立即刷新



		m_x = 300;
		m_y = 300;

		m_direct = DIRECT_RIGHT;  //初始方向为右
		//图片变量和图片资源进行绑定关联
		::loadimage(&m_imgUp, L".\\res\\mali-up.bmp");
		::loadimage(&m_imgDown, L".\\res\\mali-down.bmp");
		::loadimage(&m_imgLeft, L".\\res\\mali-left.bmp");
		::loadimage(&m_imgRight, L".\\res\\mali-right.bmp");

	}

	~CPeople() {
		//关闭窗口
		::closegraph();
	}

public:
	void ShowPeople() {
		::BeginBatchDraw(); //批量绘图

		::cleardevice();//清除上一次绘图痕迹



		//-这是我的绘图代码--------------------------------------
		if (m_direct == DIRECT_UP) ::putimage(m_x, m_y, &m_imgUp);
		if (m_direct == DIRECT_DOWN) ::putimage(m_x, m_y, &m_imgDown);
		if (m_direct == DIRECT_LEFT) ::putimage(m_x, m_y, &m_imgLeft);
		if (m_direct == DIRECT_RIGHT) ::putimage(m_x, m_y, &m_imgRight);


		//---------------------------------------
		::EndBatchDraw();

	}

	void MovePeople(int direct,int step) {
		switch (direct)
		{
		case DIRECT_UP:
		{

			m_y - step >= 0 ? m_y -= step : m_y = 0;
			/*if (m_y - step >= 0) {
				m_y -= step;
			}
			else {
				m_y = 0;
			}*/
			m_direct = DIRECT_UP;
		}
		break;
		case DIRECT_DOWN:
		{
			if (m_y + step <= 540) {
				m_y += step;
			}
			else {
				m_y = 540;
			}
			m_direct = DIRECT_DOWN;
		}
		break;
		case DIRECT_LEFT:
		{
			if (m_x - step >= 0) {
				m_x -= step;
			}
			else {
				m_x = 0;
			}
			m_direct = DIRECT_LEFT;
		}
		break;
		case DIRECT_RIGHT:
		{
			if (m_x + step <= 540) {
				m_x += step;
			}
			else {
				m_x = 540;
			}
			m_direct = DIRECT_RIGHT;
		}
		break;

		}
	}

	void Run() {
		ShowPeople();
		while (1) {
			int key = _getch();//获取按下的字符码

			if (key == KEY_ESC) {//如果是退出,则break

				int ret = ::MessageBox(NULL, L"是否退出", L"提示", MB_OKCANCEL);
				if (ret == IDOK) {//确定
					break;
				}
				
			}

			//移动
			MovePeople(key, MOVE_STEP);

			//显示
			ShowPeople();

		}



	}

};

主函数

int main()
{
	CPeople peo;
	peo.Run();

	return 0;
}

运行结果


结语

以上就是两个用类来实现的小练习了,相信在学完之后你对类会有更深层次的理解,也能够明白类的重要性了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/503248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java多线程---线程的创建(Thread类的基本使用)

本文主要介绍Java多线程的相关知识, Thread的创建, 常用方法的介绍和使用, 线程状态等. 文章目录 前言 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线程 4. 使用内部类…

【Java笔试强训 31】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;美国节日…

数组传参不理解?(数组传参的本质)

在我们编写程序时&#xff0c;经常需要传递参数给函数&#xff0c;其中一种常见的参数类型就是数组。数组作为一种数据结构&#xff0c;可以存储多个相同类型的数据元素&#xff0c;并按照一定的顺序排列。在函数中传递数组参数&#xff0c;可以方便地对数组进行操作处理。但是…

StarCoder - 源代码大模型

StarCoder 是一种在源代码和自然语言文本上训练的语言模型 (LM)。 它的训练数据包含 80 多种不同的编程语言以及从 github 问题和提交以及笔记本中提取的文本。 StarCoder 是在 github 代码上训练的&#xff0c;因此它可以用来执行代码生成。 更准确地说&#xff0c;模型可以完…

手术麻醉系统源码——业务流程介绍

采用计算机和通信技术&#xff0c;实现监护仪、麻醉机、呼吸机、输液泵等设备输出数据的自动采集&#xff0c;采集的数据能够如实准确地反映患者生命体征参数的变化&#xff0c;并实现信息高度共享&#xff0c;根据采集结果&#xff0c;综合其他患者数据&#xff0c;自动生成手…

在springboot项目中配置数据库下划线命名映射为java的驼峰命名时出错

问题 在使用spirngboot集成mybaits的时候&#xff0c;想要开启命名映射&#xff0c;如图配置 # mybatis配置 mybatis:type-aliases-package: com.zhong.springcloud.pojoconfig-location: classpath:mybatis/mybatis-config.xmlmapper-locations: classpath:mybatis/mapper/*…

4年外包出来,5次面试全挂....

我的情况 大概介绍一下个人情况&#xff0c;男&#xff0c;毕业于普通二本院校非计算机专业&#xff0c;18年跨专业入行测试&#xff0c;第一份工作在湖南某软件公司&#xff0c;做了接近4年的外包测试工程师&#xff0c;今年年初&#xff0c;感觉自己不能够再这样下去了&…

深入理解二分类和多分类CrossEntropy Loss和Focal Loss

深入理解二分类和多分类CrossEntropy Loss和Focal Loss 二分类交叉熵 在二分的情况下&#xff0c;模型最后需要预测的结果只有两种情况&#xff0c;对于每个类别我们的预测得到的概率为 p p p和 1 − p 1-p 1−p&#xff0c;此时表达式为&#xff08; 的 log ⁡ \log log底数…

如何用ChatGP协助你,从品牌角度对产品提出升级建议?

该场景对应的关键词库&#xff08;19个&#xff09;&#xff1a; 品牌洋葱图思维模型、产品信息、人群、品类、属性、体验、差异化特征、功效、品牌价值主张、目标用户、需求、痛点、爽点、消费者、外观、功能、结构、产品优化建议、产品开发可行性。 提问模板(3个&#xff09…

《Vue.js 设计与实现》—— 01 权衡的艺术

书籍链接&#xff1a;https://weread.qq.com/web/bookDetail/c5c32170813ab7177g0181ae 框架设计里到处都体现了权衡的艺术。 当我们设计一个框架时&#xff0c;框架本身的各个模块之间并不是相互独立的&#xff0c;而是相互关联、相互制约的。 作为框架设计者&#xff0c;一…

Windows10安装免安装版redis

下载 官方下载地址&#xff1a;github.com/MicrosoftAr…选择版本 解压安装 配置环境变量&注册成服务 配置环境变量 以管理员启动命令行&#xff0c;在redis安装根目录&#xff0c;把redis注册服务 redis-server --service-install redis.windows-service.conf --lo…

Communications chemisty|德睿智药工作-用于分子性质预测的药物约束异构图Transformer模型

德睿智药的分子性质预测任务 题目&#xff1a; Pharmacophoric-constrained heterogeneous graph transformer model for molecular property prediction 文献来源&#xff1a;COMMUNICATIONS CHEMISTRY | (2023) 6:60 | 代码&#xff1a;https://github.com/stardj/PharmHG…

springboot+dubbo+zookeeper 项目实战

现在有一段代码再前台&#xff0c;后台系统中都存在&#xff0c;都需要这段代码&#xff0c;存在这种情况&#xff0c;我们可以选择将这段代码提取出来作为一个服务&#xff0c;让前台和后台系统作为消费者远程调用这段代码&#xff0c;提高了代码的复用性。 springboot集成dub…

Unity Audio -- (2)创建动态音效

评估场景需求 本节的目标是添加脚步声到角色身上&#xff0c;当角色走路时&#xff0c;触发动画事件并播放声音。 脚步声是我们在真实世界中常常被我们所忽视的声音&#xff0c;但脚步声能够传达出许多环境信息。你现在可以花一小段时间绕着你周围的环境走一走并仔细听听脚步声…

CLIP : Learning Transferable Visual Models From Natural Language Supervision

CLIP : Learning Transferable Visual Models From Natural Language Supervision IntroductionApproach Introduction 在raw的数据上自监督的训练模型&#xff0c;已经在NLP领域取得了革命性进展&#xff0c;这种模型需要收到硬件、数据的限制&#xff0c;但是能得到很好的迁…

算法 DAY55 动态规划11 392.判断子序列 115.不同的子序列

392.判断子序列 本题可以直接用双指针解法。但是本题是编辑距离的入门题目&#xff0c;故采用动态规划解法为后序“编辑距离”类题目打基础。 本题与最大子序列非常相似&#xff0c;但不同的是s必须连续&#xff0c;t可以不连续。 五部曲 1、dp[i][j] 表示以下标i-1为结尾的字…

Seata介绍

介绍&#xff1a; Seata的设计目标是对这个业务无侵入&#xff0c;因此从业务无侵入的2PC方案开始的&#xff0c;在传统的2PC的基础上演进的。它把一个分布式事务拆分理解成一个包含了若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致性&#xff0c;要…

25.自定义注解

自定义注解 一、什么是注解 Annontation是Java1.5开始引入的新特征&#xff0c;中文名称叫注解。 它提供了一种安全的类似注释的机制&#xff0c;用来将信息或元数据&#xff08;metadata&#xff09;与程序元素&#xff08;类、方法、成员变量等&#xff09;进行关联。为程序…

大数据技术之SparkSQL——数据的读取和保存

一、通用的加载和保存方式 SparkSQL提供了通用的保存数据和数据加载的方式。根据不同的参数读取&#xff0c;并保存不同格式的数据。SparkSQL默认读取和保存的文件格式为Parquet。 1.1 加载数据 spark.read.load 是加载数据的通用方式。 如果读取不同格式的数据&#xff0c;可…

如何编译DPDK静态库

阅读前面文章https://blog.csdn.net/qq_36314864/article/details/130243348,知道了哪些dpdk文件可以在windows下生成。 打开vs,新建一个生成静态库工程,在生成的lib文件中找到D:\dpdk-21.07\build\lib D:\dpdk-21.07\build\drivers找到对应的文件,并按照路径,新建筛选项…