07功能之装备系统的实现

07功能之装备系统的实现

前提:
我们知道,C++功能系统的实现思想是:继承和组合,优先使用组合。原因是组合可以更多的节省代码,而继承代码多,并且继承下来成员很混乱。 但是作者这里就使用了继承,哈哈,组合的话大家自己去试着实现。

1 整个装备系统的框架逻辑
1)英雄与装备的关系:装备继承后仍是英雄。
在这里插入图片描述

2)对业务层的代码分析可得出,每一个装备对象都是由上一个对象(装备类或者英雄类)的数据赋值得到,然后上一对象被释放,剩下的对象成为新英雄对象。
在这里插入图片描述

2 思考如何实现抽象类,即上面的英雄基类和装备基类
1)继承时,抽象类有数据的,是在抽象类提供构造自己初始化,然后给子类调用;还是子类自己在自己的构造初始化抽象类的数据呢?
答:虽然抽象类提供构造给子类调用很方便,但是有时会比较混乱。所以这里建议是子类统一自己初始化,方便整个逻辑清晰。并且一般抽象类都是提供纯虚函数的方法,其他都不需要处理。但抽象类若是继承于另一抽象类的,构造一般会实现,例如抽象装备类。

注:我这里写抽象英雄类时是实现了构造,做反例。想要工整的代码去查看我以前写的设计模式3的装饰模式。

class AbstractHero {
public:
	//AbstractHero() { mHp = 0; } 不建议实现构造,由子类提供初始化
//私有子类不能访问 必须是保护或者公有
public:
	int mHp;  //英雄血量
};

2)继承时,英雄的显示状态函数是声明在装备基类还是英雄基类呢?
答:必须写在英雄基类才能给所有英雄显示状态。若写在装备基类,当AbstractHero *hero= new HeroA;时,指针hero是无法调用到装备类的方法。
3)由于是继承,我们为了析构基类的对象时,也能够析构子类的析构函数,抽象类一般也会声明析构函数为虚函数。

4)代码讲述抽象类,方便更好的理解抽象类的实现。

class AbstractHero {
public:
	//这个一般不实现,因为抽象类不可实例化,虽然有数据时,方便子类统一调用赋值,但混乱
	//以后有数据的也不要在抽象类定义构造赋值,统一子类中赋值,方便逻辑清晰
	AbstractHero() { mHp = 0; }      //不建议的写法,这里做反例

	//这个函数抽象类基本都要实现
	virtual ~AbstractHero(){}

	//英雄状态显示,所以英雄必须都能显示,不能写在装备抽象类,否则英雄无法显示
	virtual void ShowHeroStatus() = 0;

public:
	int mHp;  //英雄血量
};

3 如何实现装备具体类
1)实际上,实现装备具体类是不难的,就是在原本英雄的情况下改变他的属性值赋给装备的数据即可。一般有构造改变、Set方法改变。例如:
这里需要注意的是:必须是上一英雄数据+改变定值赋给本类的数据,即装备类。
this->mHp代表装备类的数据,而this->mHero->mHp是上一英雄的数据。

	Wujin(AbstractHero *hero) :AbstractEquipment(hero) {   
		// 属性值的改变,即当前数据 = 上一英雄数据 + 装备值
		this->mHp = this->mHero->mHp + 40;
	}     
	// 通过方法设置英雄
	virtual void SetHero(AbstractHero *hero) {     
		this->mHero = hero; 
		this->mHp = this->mHero->mHp + 40;             
	} 

4 下面给出完整代码:

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
using namespace std;

class AbstractHero {
public:
	

	//这个一般不实现,因为抽象类不可实例化,虽然有数据时,方便子类统一调用赋值,但混乱
	//以后有数据的也不要在抽象类定义构造赋值,统一子类中赋值,方便逻辑清晰
	AbstractHero() { mHp = 0; }      //不建议的写法,这里做反例

	//这个函数抽象类基本都要实现
	virtual ~AbstractHero(){}

	//英雄状态显示,所以英雄必须都能显示,不能写在装备抽象类,否则英雄无法显示
	virtual void ShowHeroStatus() = 0;

//私有子类不能访问 必须是保护
public:
	int mHp;  //英雄血量
};

class HeroA :public AbstractHero {
public:
	HeroA():AbstractHero() { 
		//this->mHp = 0;//基类不实现就这样写 
	}
	virtual void ShowHeroStatus() {
		cout << "英雄A血量=" << mHp << endl;
	}
};

class HeroB :public AbstractHero {
public:
	HeroB():AbstractHero(){}
	virtual void ShowHeroStatus() {
		cout << "英雄B血量=" << mHp << endl;
	}
};


//装备抽象类(不允许实例化为对象) 继承仍是英雄
class  AbstractEquipment :public AbstractHero {

public:
	//注:构造函数不能时虚函数
	AbstractEquipment():AbstractHero() { this->mHero = NULL; }
	virtual ~AbstractEquipment(){}

	AbstractEquipment(AbstractHero *hero):AbstractHero() {
		this->mHero = hero;
	}
	//外部方法设置英雄
	virtual void SetHero(AbstractHero *hero) = 0;   //这种写法子类必须实现,空阔号则不用,看个人

	//展示穿上装备后的英雄数据
	virtual void ShowHeroStatus() {};

protected:
	AbstractHero *mHero;        //写在抽象类方便子类统一调用该抽象类的构造
};


//无尽装备 (装备类重点:最重要的两个函数就是设置英雄。相当于给英雄穿上装备。)
class Wujin :public AbstractEquipment {
public:
	Wujin():AbstractEquipment() {}
	// 通过构造设置英雄
	Wujin(AbstractHero *hero) :AbstractEquipment(hero) {   
		// 属性值的改变,即当前数据 = 上一英雄数据 + 装备值
		this->mHp = this->mHero->mHp + 40;
	}     
	// 通过方法设置英雄
	virtual void SetHero(AbstractHero *hero) {     
		this->mHero = hero; 
		this->mHp = this->mHero->mHp + 40;             
	}  
	virtual void ShowHeroStatus() {
		cout << "穿上无尽后的血量" << this->mHp << endl;

		delete[] this->mHero;
		this->mHero = NULL;
	}

	~Wujin() {
		if (this->mHero != NULL) {
			//delete[] this->mHero;   //写析构的话必须delete[] Wujin才能释放原英雄,所以暂时写在Show
			//this->mHero = NULL;
		}
	}
private:
	//Wujin *mWu;    //不需要
};

//狂徒装备 
class Kuangtu :public AbstractEquipment {
public:
	Kuangtu() :AbstractEquipment() {}
	// 通过构造设置英雄
	Kuangtu(AbstractHero *hero) :AbstractEquipment(hero) {
		// 穿上狂徒后的英雄属性值改变(可以单独写一个方法) 注:是每次用上一个英雄赋值给当前装备成为新英雄
		this->mHp = this->mHero->mHp + 20;  
	}
	// 通过方法设置英雄
	virtual void SetHero(AbstractHero *hero) {
		this->mHero = hero;
		this->mHp = this->mHero->mHp + 20;
	}

	// 必须在抽象英雄类声明
	virtual void ShowHeroStatus() {
		cout << "穿上狂徒后的血量" << this->mHp << endl;

		delete[] this->mHero;
		this->mHero = NULL;
	}

	~Kuangtu() {}
private:
};


void test01() {

	// 注:是每次用上一个英雄赋值给当前装备成为新英雄,上一英雄被释放

	AbstractHero *heroA = new HeroA;
	//英雄没有装备
	heroA->ShowHeroStatus();

	cout << "===========" << endl;

	//穿上无尽
	heroA = new Wujin(heroA);
	heroA->ShowHeroStatus();
	//delete[] heroA->mHero;释放原英雄时,由于protected只能在类内释放

	cout << "===========" << endl;

	//穿上狂徒
	heroA = new Kuangtu(heroA);
	heroA->ShowHeroStatus();


	//最后释放调用该英雄
	delete[] heroA;
}

int main() {

	test01();

	return 0;
}

5 总结
1)抽象类的实现:
第一层的抽象类一般只提供纯虚方法,不实现构造;第二层即抽象类继承抽象类时,构造一般都会提供。其实这些都是看经验或者个人的,没有规定死的;
2)装备类的实现:
装备具体类其实就是提供改变属性值的方法;
3)内存关系:
每次用原英雄给新装备赋值,并释放掉原英雄,这样新装备就变成了新的英雄。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值