一. 类封装
问题:数据和算法彼此独立,关联性不强
class:定义类的关键字,类名一般以C开头
访问修饰符:描述了类中成员所能使用的一个范围,即权限限制,默认是private(私有的)
public:类成员在任何地方都可以使用
protected:在类中和子类中可以使用
private:只能在类中使用
成员属性/变量:类对象的属性也称为成员变量
成员方法:使用成员方法对应于类对象的行为
当方法的局部变量和类的成员变量重名时,就近原则优先使用局部变量,成员变量被屏蔽。此时若要使用成员变量,就需要用 “this->成员变量名” 的格式来引用成员变量
#include <iostream>
using namespace std;
class CPeople { //抽象
public:
string name; //名字
private:
int m_nAge; //年龄
protected:
bool m_bSex; //性别
public:
void eat() {
cout << name << " eating" << endl;
}
void show() {
cout << name << " " << m_nAge << " " << m_bSex << endl;
}
//公共的接口函数
void Init(string name) {
this->name = name;
m_nAge = 21;
m_bSex = 1;
}
};
int main() {
//具体
CPeople peo; //类 类名的变量,称之为 对象
peo.name = "张三";
peo.eat();
peo.Init("李四");
peo.show();
}
class命名习惯:
类名 "C"开头
成员变量 "m_"+数据类型"n"(int)+变量名
1.1 构造函数
若采取上述的初始化方式,每一次定义类都要调用一遍,有没有一种可以在定义时自动初始化的方式呢?
构造函数:函数名为当前的类名,没有返回类型(不是void)
参数:如果没有手动重构 构造函数,编译器会默认添加构造函数,默认无参构造
如果是手动重构的话,编译器就不会提供,默认无参构造,可以根据实际情况 自行添加参数
CPeople() {
m_strName = "阿里巴巴";
m_nAge = 20;
m_bSex = 0;
}
//一个类中构造函数可以存在多个。它们之间的关系是重载
CPeople(string name, int age, bool sex) {
m_strName = name;
m_nAge = age;
m_bSex = sex;
}
作用:用来给类中的成员属性做初始化。定义对象时,编译器自动调用构造函数
默认无参构造函数体代码->为空 CPeople() {},多数情况下,需要手动重构构造函数
一个类中可以有多个构造函数,但对象创建时只会执行其中一个
1.2 析构函数
函数名:~Cpeople ,没有返回类型,无参数
编译器默认提供的默认析构函数,则函数体代码为空
作用:用来回收类中成员 额外申请的 空间
调用时间:对象的生命周期结束时,编译器会自动调用析构函数(编译器先调用析构函数回收额外申请的空间,再由编译器回收对象本身的空间)
char* m_pNote = new char[] {"abcd"};
~CPeople() {
if (m_pNote)
delete[] m_pNote;
m_pNote = nullptr;
}
析构函数一个类中永远只会存在一个
空类默认产生的成员函数
构造函数、拷贝构造函数、析构函数、赋值运算符、取址运算符、取址运算符 const
class Empty{ public: Empty();// 缺省构造函数 Empty(const Empty&);// 拷贝构造函数 ~Empty();// 析构函数 Empty& operator=(const Empty& ); // 赋值运算符 Empty* operator&();// 取址运算符 const Empty* operator&() const;// 取址运算符 const };
二. 链表封装(类)
#include <iostream>
using namespace std;
/*
在C++ 中 结构体 和 类的区别:
1. 结构体 默认的访问修饰符 为 public, 类的默认访问修饰符 private
2. 结构体 默认继承方式 为 public,类 默认继承方式 为 private,
*/
typedef struct node {
int data;
node* next;
node(int data) {
this->data = data;
next = nullptr;
}
}Node,*PNode;
class CLinkedList {
private:
PNode header;
PNode ender;
int len;
public:
CLinkedList() {
header = ender = nullptr;
len = 0;
}
~CLinkedList() {
PNode temp;
while (header) {
temp = header;
header = header->next;
delete temp; //释放指针指向的内存
temp = nullptr; //指针赋空,避免非法性判断
len--;
}
}
void PushBack(int data) {
PNode p = new Node(data); //堆区
if (len == 0)
header = ender = p; //指针指向节点所申请的空间
else {
ender->next = p;
ender = p;
}
len++;
}
void PopFront() {
if (header) {
PNode temp = header;
if (header == ender) {
header = ender = nullptr;
}
else {
header = header->next;
}
delete temp;
temp = nullptr;
len--;
}
}
void showList() {
PNode p = header;
while (p) {
cout << p->data << ' ';
p = p->next;
}
cout << endl;
}
int getLen() {
return len;
}
};
int main() {
Node p(1);
CLinkedList list;
list.PushBack(10);
list.PushBack(20);
list.PushBack(30);
list.PushBack(40);
list.PushBack(50);
list.showList();
cout << list.getLen() << endl;
list.PopFront();
list.showList();
cout << list.getLen() << endl;
}
三. 人物移动
#include <iostream>
#include <easyx.h>
#include <conio.h> //控制台输入
using namespace std;
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define ESC 27
#define MOVE_STEP 10
const int screenWidth = 600;
const int screenHeight = 600;
class CPeople {
private:
//人物显示的坐标
int m_x, m_y;
//图片绑定
IMAGE m_up, m_down, m_left, m_right;
int m_direct;
public:
CPeople() {
//::将函数限制在当前作用域,防止class中有重名方法
::initgraph(screenWidth, screenHeight); //创建窗口
::setbkcolor(RGB(233, 101, 123)); //设定背景颜色
::cleardevice(); //使背景颜色立即生效,不然只有到窗口有绘制操作时才会更新
m_x = screenWidth / 2;
m_y = screenHeight / 2;
//图片变量 和 具体的图片资源绑定
::loadimage(&m_up, L".\\res\\up.bmp");
::loadimage(&m_down, L".\\res\\down.bmp");
::loadimage(&m_left, L".\\res\\left.bmp");
::loadimage(&m_right, L".\\res\\right.bmp");
m_direct = KEY_RIGHT; //初始方向为右
}
~CPeople() {
::closegraph(); //关闭窗口
}
void showPeople() {
::cleardevice();
//开始批量重绘
::BeginBatchDraw();
if(m_direct==KEY_UP)
::putimage(m_x, m_y, &m_up);
if (m_direct == KEY_DOWN)
::putimage(m_x, m_y, &m_down);
if (m_direct == KEY_LEFT)
::putimage(m_x, m_y, &m_left);
if (m_direct == KEY_RIGHT)
::putimage(m_x, m_y, &m_right);
//结束批量重绘
::EndBatchDraw();
}
void MovePeople(int direct) { //键盘传递方向
switch (direct) {
case KEY_UP:
if (m_y - MOVE_STEP >= 0)
m_y -= MOVE_STEP;
else m_y = 0;
break;
case KEY_DOWN:
if (m_y + MOVE_STEP <= screenHeight - 60)
m_y += MOVE_STEP;
else m_y = screenHeight - 60;
break;
case KEY_LEFT:
if (m_x - MOVE_STEP >= 0)
m_x -= MOVE_STEP;
else m_x = 0;
break;
case KEY_RIGHT:
if (m_x + MOVE_STEP <= screenWidth - 60)
m_x += MOVE_STEP;
else m_x = screenWidth - 60;
break;
default:
direct = m_direct;
}
m_direct = direct; //更新方向
}
void RunGame() {
showPeople();
while (1) {
//不打断获取方向键
int key = _getch(); //获取键盘按键的字符码
if (key == ESC) {
int ret = ::MessageBox(NULL, L"确定退出嘛?", L"提示", MB_YESNO); //弹出弹出框
if (ret == IDYES) {
break;
}
else { //IDNO
continue;
}
}
//如果获取到了,调用移动的方法,传参
MovePeople(key);
//刷新窗口 显示人物
showPeople();
}
}
};
int main() {
CPeople p;
p.RunGame();
}