【C++】 类练习---封装链表、人物移动
目录
前言
正文
结构体和类的区别
练习1:封装链表
用类封装链表的注意事项
定义一个链表的节点结构
链表类代码
主函数
运行结果
练习2:人物移动
说明
头文件以及宏
人物类
主函数
运行结果
结语
前言
在学完了【C++】 类基础汇总(类封装,构造、析构函数...)后,我们明白了类的特性以及使用方法,那么就需要用一些实例来巩固一下知识点,所以这篇文章就教你如何用类来封装链表和用类来写一个人物移动的小项目。
正文
结构体和类的区别
C++中的结构体和类很像,可以有构造-析构,也有访问修饰符,继承、多态等。区别有两点:
- 类成员属性:方法默认是私有的(private),而结构体默认是公有的(public)。
- 当从基类、结构体中继承时,类的默认继承方式是私有的(private),而结构体是公有的(public)。
此外在使用习惯上看也略有差别:一般情况,使用类来描述功能实现,而结构体通常只是纯粹的表示数据。比如链表有复杂的数据、很多的方法一般定义成类,而节点只是描述了持有数据的类型和指向下一个节点的指针,一般被定义为结构体。
练习1:封装链表
用类封装链表的注意事项
在使用类封装链表时,需要注意以下几点:
-
将链表的节点定义为类中的一个私有内部类,这个内部类应该至少包含两个成员变量:当前节点的值和指向下一个节点的指针。
-
类中应该包含头节点和尾节点的指针。头节点是第一个有效节点之前的虚拟节点,尾节点是最后一个有效节点。
-
需要实现一些基本的方法,如增加节点、删除节点、查找节点、获取链表长度、判断链表是否为空等。这些方法应该被定义为公有成员函数,以方便外部调用。
-
在进行插入或删除操作时,需要注意更新头节点和尾节点的指针。如果链表为空,则插入第一个节点时应同时将头节点和尾节点指向新插入的节点。
-
要防止内存泄漏问题,需要在析构函数中对链表中的所有节点进行释放。
定义一个链表的节点结构
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;
}
运行结果
结语
以上就是两个用类来实现的小练习了,相信在学完之后你对类会有更深层次的理解,也能够明白类的重要性了。