多态

1静态联编和动态联编

1.1多态分类
1.1.1静态多态 函数重载
1.1.2动态多态 虚函数 继承关系
1.2静态联编
1.2.1地址早绑定 编译阶段绑定好地址
1.3动态联编
1.3.1地址晚绑定 ,运行时候绑定好地址
1.4多态
1.4.1父类的引用或指针指向子类对象

test.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

	virtual void eat()
	{
		cout << "动物在吃饭" << endl;
	}

};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}

	virtual void eat()
	{
		cout << "小猫在吃鱼" << endl;
	}
};

//调用doSpeak ,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址
//如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址
//动态联编,写法 doSpeak方法改为虚函数,在父类上声明虚函数,发生了多态
// 父类的引用或者指针 指向 子类对象
void doSpeak(Animal & animal) //Animal & animal = cat
{
	animal.speak();
}
//如果发生了继承的关系,编译器允许进行类型转换

void test01()
{
	Cat cat;
	doSpeak(cat);

}


void test02()
{
	//cout << sizeof(Animal) << endl;
	//父类指针指向子类对象 多态
	Animal * animal = new Cat;

	//animal->speak();
	// *(int*)*(int*)animal 函数地址
	((void(*)()) (*(int*)*(int*)animal))();

	//  *((int*)*(int*)animal+1)猫吃鱼的地址

	((void(*)()) (*((int*)*(int*)animal + 1)))();
}

int main(){

	//test01();

	test02();

	system("pause");
	return EXIT_SUCCESS;
}

2多态原理解析

在这里插入图片描述
2.1当父类中有了虚函数后,内部结构就发生了改变
2.2内部多了一个 vfprt
2.2.1virtual function pointer 虚函数表指针
2.2.2指向 vftable 虚函数表
2.3父类中结构 vfptr &Animal::speak
2.4子类中 进行继承 会继承 vfptr vftable
2.5构造函数中 会将虚函数表指针 指向自己的虚函数表
2.6如果发生了重写,会替换掉虚函数表中的原有的speak,改为 &Cat::speak
2.7深入剖析,内部到底如何调用
2.8((void()()) ((int*)(int)animal))();
2.9猫吃鱼的函数调用(编译器的调用)

3多态案例 – 计算器案例

3.1早期方法 是不利于扩展
3.2开发有原则 开闭原则 – 对扩展开放 对修改关闭
3.3利用多态实现 – 利于后期扩展,结构性非常好,可读性高, 效率稍微低,发生多态内部结构复杂

02 多态案例-计算器案例.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//class Calculator
//{
//public:
//
//	void setv1(int v)
//	{
//		this->val1 = v;
//	}
//
//	void setv2(int v)
//	{
//		this->val2 = v;
//	}
//
//
//	int getResult(string oper)
//	{
//		if (oper == "+")
//		{
//			return val1 + val2;
//		}
//		else if (oper == "-")
//		{
//			return val1 - val2;
//		}
//	}
//private:
//	int val1;
//	int val2;
//
//};
//
//void test01()
//{
//	Calculator cal;
//	cal.setv1(10);
//	cal.setv2(10);
//	cout << cal.getResult("+") << endl;
//	cout << cal.getResult("-") << endl;
//
//}

//真正的开发中,有个开发原则 开闭原则
// 对扩展开放  对修改关闭


//利用多态实现计算器
class abstractCalculator
{
public:

	//虚函数 virtual int getResult(){ return 0; };

	//纯虚函数
	//如果父类中有了 纯虚函数  子类继承父类,就必须要实现 纯虚函数
	//如果父类中 有了 纯虚函数 ,这个父类 就无法实例化对象了
	//这个类有了纯虚函数,通常又称为 抽象类
	virtual int getResult()  = 0;


	void setv1(int v)
	{
		this->val1 = v;
	}

	void setv2(int v)
	{
		this->val2 = v;
	}

public:
	int val1;
	int val2;

};

//如果父类中有了 纯虚函数  子类继承父类,就必须要实现 纯虚函数
class A:public abstractCalculator
{
public:
	virtual int getResult()
	{
		return 0;
	}
};

//加法计算器
class PlusCalculator :public abstractCalculator
{
public:
	virtual int getResult()
	{ 
		return val1 + val2;
	};
};
class SubCalculator : public abstractCalculator
{
public:
	virtual int getResult()
	{
		return val1 - val2;
	};
};
class ChengCalculator :public abstractCalculator
{
public:
	virtual int getResult()
	{
		return val1 * val2;
	};

};

void test02()
{
	abstractCalculator * abc ; 
	//加法计算器
	abc =  new PlusCalculator;

	abc->setv1(10);
	abc->setv2(20);

	cout << abc->getResult() << endl;

	delete abc;

	abc = new SubCalculator;
	abc->setv1(10);
	abc->setv2(20);
	cout << abc->getResult() << endl;

	delete abc;

	abc = new ChengCalculator;
	abc->setv1(10);
	abc->setv2(20);
	cout << abc->getResult() << endl;


	//如果父类有了纯虚函数,不能实例化对象了
	/*abstractCalculator aaa;
	abstractCalculator * abc = new abstractCalculator;*/

}

int main(){

	//test01();

	test02();

	system("pause");
	return EXIT_SUCCESS;
}

4抽象类 和 纯虚函数

4.1纯虚函数写法 virtual void func() = 0;
4.2抽象类型
4.3抽象类 不可以实例化对象
4.4如果类 继承了抽象类, 必须重写抽象类中的纯虚函数

5虚析构和纯虚析构

5.1虚析构
5.1.1virtual ~类名() {}
5.1.2解决问题: 通过父类指针指向子类对象释放时候不干净导致的问题
5.2纯虚析构函数
5.2.1写法 virtual ~类名() = 0
5.2.2类内声明 类外实现
5.2.3如果出现了纯虚析构函数,这个类也算抽象类,不可以实例化对象

03 虚析构和纯虚析构.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Animal
{
public:

	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

	//普通析构 是不会调用子类的析构的,所以可能会导致释放不干净
	//利用虚析构来解决这个问题
	//virtual ~Animal()
	//{
	//	cout << "Animal的析构调用" << endl;
	//}

	//纯虚析构 写法如下 
	//纯虚析构 ,需要声明 还需要实现 类内声明,类外实现
	virtual ~Animal() = 0;
	//如果函数中出现了 纯虚析构函数,那么这个类也算抽象类
	//抽象类 不可实例化对象

};
Animal::~Animal()
{
	//纯虚析构函数实现
	cout << "Animal的纯虚析构调用" << endl;
}
// 如果出现纯虚析构,类也算抽象类,不能实例化对象
//void func()
//{
//	Animal an;
//	Animal * animal = new Animal;
//}

class Cat:public Animal
{
public:
	Cat(const char * name)
	{
		this->m_Name = new char[strlen(name) + 1];
		strcpy(this->m_Name, name);
	}

	virtual void speak()
	{
		cout << "小猫在说话" << endl;
	}

	~Cat()
	{
		cout << "Cat的析构调用" << endl;
		if (this->m_Name !=NULL)
		{
			delete[] this->m_Name;
			this->m_Name = NULL;
		}
	}

	char * m_Name;

};


void test01()
{
	Animal * animal = new Cat("TOM");
	animal->speak();

	delete animal;

}


int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

6向上类型转换和向下类型转换

在这里插入图片描述
6.1基类转派生类
6.1.1向下类型转换 不安全的
6.2派生类转 基类
6.2.1向上类型转换 安全
6.3如果发生多态
6.3.1总是安全的
6.4父类中如果写了虚函数,而子类没有任何重写,有意义吗?
6.4.1没有意义

PK案例

在这里插入图片描述
Weapon.h

#pragma  once
#include <iostream>
#include <string>
using namespace std;

//抽象类
class Weapon
{
public:
	//获取基础伤害
	virtual int getBaseDamage() = 0;

	//获取吸血
	virtual int getSuckBlood() = 0;

	//获取是否定身
	virtual bool getHold() = 0;

	//获取是否暴击
	virtual bool getCrit() = 0;


	string m_WeaponName; //武器名称
	int m_BaseDamage; //基础伤害
};

Hero.h

#pragma once 
#include <iostream>
#include "Weapon.h"
#include <string>
#include "Monster.h"
using namespace std;

class Monster;

class Hero
{
public:
	Hero();

	string m_Name; //人名

	int m_Atk; //攻击力

	int m_Def; // 防御力

	int m_Hp; //血量

	Weapon * weapon; //武器

	void EquipWeapon(Weapon * weapon);

	void Attack( Monster * monster );
};

Knife.h

#pragma once 
#include <iostream>
#include "Weapon.h"
#include <string>
using namespace std;


class Knife :public Weapon
{
public:
	Knife();

	//获取基础伤害
	virtual int getBaseDamage();

	//获取吸血
	virtual int getSuckBlood();

	//获取是否定身
	virtual bool getHold();

	//获取是否暴击
	virtual bool getCrit();

};

DragonSword.h

#pragma once 
#include <iostream>
#include "Weapon.h"
#include <string>
using namespace std;

class DragonSword:public Weapon
{
public:
	DragonSword();

	//获取基础伤害
	virtual int getBaseDamage() ;

	//获取吸血
	virtual int getSuckBlood();

	//获取是否定身
	virtual bool getHold();

	//获取是否暴击
	virtual bool getCrit();

	//  吸血率  定身率 暴力率 
	int suckRate;
	int holdRate;
	int critRate;

	//传入概率 判断是否触发
	bool isTrigger(int rate);
};

Monster.h

#pragma once 
#include <iostream>
#include "Weapon.h"
#include <string>
#include "Hero.h"
using namespace std;

class Hero;

class Monster
{
public:
	Monster();

	string m_Name;

	int m_Hp;

	int m_Atk;

	int m_Def;

	bool m_Hold;

	void Attack(Hero * hero);

};

Hero.cpp

#include "Hero.h"

Hero::Hero()
{
	this->m_Hp = 500;

	this->m_Atk = 50;

	this->m_Def = 50;

	this->m_Name = "刘法师";

	this->weapon = NULL;

}

//装备武器
void Hero::EquipWeapon(Weapon * weapon)
{
	this->weapon = weapon;

	cout << "英雄:" << this->m_Name << " 装备了武器 << " << this->weapon->m_WeaponName << " >> " << endl;

}
//攻击
void Hero::Attack(Monster * monster)
{
	int damage = 0;
	int addHp = 0;
	bool isHold = false;
	bool isCrit = false;

	if (this->weapon == NULL) //武器为空 没有加成
	{
		damage = this->m_Atk;
	}
	else
	{
		//基础伤害
		damage = this->m_Atk + this->weapon->getBaseDamage();
		//计算吸血
		addHp = this->weapon->getSuckBlood();
		//计算定身
		isHold = this->weapon->getHold();
		//计算暴击
		isCrit = this->weapon->getCrit();
	}
	if (isCrit) //暴击 伤害 加成
	{
		damage = damage * 2;
		cout << "英雄的武器触发了暴击效果,怪物收到了双倍的伤害,伤害值:" << damage << endl;
	}
	if (isHold)
	{
		cout << "英雄的武器触发了定身效果,怪物停止攻击一回合"<< endl;
	}
	if (addHp > 0)
	{
		cout << "英雄的武器触发了吸血效果,英雄增加的血量为" << addHp << endl;
	}

	//设置怪物定身
	monster->m_Hold = isHold;

	//计算真实伤害
	int trueDamage = (damage - monster->m_Def) > 0 ? damage - monster->m_Def : 1;

	monster->m_Hp -= trueDamage;

	this->m_Hp += addHp;

	cout << "英雄" << this->m_Name << "攻击了敌人 " << monster->m_Name << "造成了 伤害" << trueDamage << endl;
}

Knife.cpp

#include "Knife.h"


Knife::Knife()
{
	this->m_BaseDamage = 10;

	this->m_WeaponName = "ะกตถ";
}

int Knife::getBaseDamage()
{

	return this->m_BaseDamage;

}

int Knife::getSuckBlood()
{
	return 0;
}

bool Knife::getHold()
{
	return false;
}

bool Knife::getCrit()
{
	return false;
}

DragonSword.cpp

#include "DragonSword.h"

DragonSword::DragonSword()
{
	this->m_BaseDamage = 20;
	this->m_WeaponName = "屠龙宝刀";
	this->suckRate = 20;
	this->holdRate = 30;
	this->critRate = 35;

}

int DragonSword::getBaseDamage()
{
	return this->m_BaseDamage;
}

int DragonSword::getSuckBlood()
{
	if (isTrigger(suckRate))
	{
		return this->m_BaseDamage * 0.5;  //按照武器基础伤害一半吸血
	}
	return 0;
}

bool DragonSword::getHold()
{
	if (isTrigger(holdRate))
	{
		return true;
	}
	return false;
}

bool DragonSword::getCrit()
{
	if (isTrigger(critRate))
	{
		return true;
	}
	return false;
}

bool DragonSword::isTrigger(int rate)
{
	//通过isTrigger判断是否触发特效
	//随机 1~100的数字

	int num = rand() % 100 + 1;
	if (num < rate)
	{
		return true;
	}
	return false;
}

Monster.cpp

#include "Monster.h"


Monster::Monster()
{
	this->m_Hp = 300;

	this->m_Atk = 70;

	this->m_Def = 40;

	this->m_Hold = false;

	this->m_Name = "比克大魔王";
}

void Monster::Attack(Hero * hero)
{
	if (this->m_Hold)
	{
		cout << "怪物" << this->m_Name << "被定身了,本回合无法攻击" << endl;
		return;
	}

	//计算攻击伤害
	int damage = (this->m_Atk - hero->m_Def) > 0 ? this->m_Atk - hero->m_Def : 1;

	hero->m_Hp -= damage;

	cout << "怪物" << this->m_Name << "攻击了英雄 " << hero->m_Name << "造成了 伤害" << damage << endl;

}

04 多态案例二-PK小游戏.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include "Hero.h"
#include "Monster.h"
#include "Weapon.h"
#include "Knife.h"
#include "DragonSword.h"
#include <ctime>
using namespace std;

void play()
{
	//创建怪物
	Monster * monster = new Monster;
	//创建英雄
	Hero * hero = new Hero;

	//创建武器
	Weapon * kinfe = new Knife;
	Weapon * dragon = new DragonSword;

	//让用户选择 武器

	cout << "请选择武器:" << endl;
	cout << "1. 赤手空拳" << endl;
	cout << "2. 小刀" << endl;
	cout << "3. 屠龙刀" << endl;

	int oper;
	cin >> oper;
	switch (oper)
	{
	case 1:
		cout << "你真牛X,你还是太年轻了!" << endl;
		break;
	case 2:
		hero->EquipWeapon(kinfe);
		break;
	case 3:
		hero->EquipWeapon(dragon);
		break;
	}

	getchar(); //输入缓冲区里有个回车 ,多获取一次值

	int round = 1;

	while (true)
	{
		getchar();

		system("cls");

		cout << "----- 当前第 " << round << " 回合开始 ------" << endl;

		if (hero->m_Hp <= 0)
		{
			cout << "英雄" << hero->m_Name << "已挂 ,游戏结束" << endl;
			break;
		}
		hero->Attack(monster);

		if (monster->m_Hp <= 0)
		{
			cout << "怪物" << monster->m_Name << "已挂,顺利通关" << endl;
			break;
		}
		monster->Attack(hero);


		if (hero->m_Hp <= 0)
		{
			cout << "英雄" << hero->m_Name << "已挂 ,游戏结束" << endl;
			break;
		}

		cout << "英雄" << hero->m_Name << "剩余血量:" << hero->m_Hp << endl;
		cout << "怪物" << monster->m_Name << "剩余血量:" << monster->m_Hp << endl;

		round++;


	}

	delete monster;
	delete hero;
	delete kinfe;
	delete dragon;

}

int main(){

	srand((unsigned int)time(NULL));

	play();


	system("pause");
	return EXIT_SUCCESS;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值