C++学习_多态

Posted Leslie X徐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++学习_多态相关的知识,希望对你有一定的参考价值。

虚函数&多态

对于一般的函数,编译器会根据指针的类型来选择; 而对于虚函数,编译器会忽略指针类型,根据指针的指向来选择函数。
有了虚函数,基类指针指向基类对象时就使用基类的成员,指向派生类对象时就使用派生类的成员。所以说,基类指针可以按照基类方式来做事也可以按照派生类方式来做事,它有多种形态、多种表现形式,这种现象就称为多态(Polymorphism)

构成多态的条件:

  • 必须存在继承关系
  • 继承关系中必须有同名的虚函数,并且他们是覆盖关系(函数原型相同)
  • 存在基类的指针(或引用),通过该指针调用虚函数。

关于虚析构函数

  • 若不设置虚析构函数,基类型指针只会执行基类的析构函数,只有派生类指针可以执行派生和基类析构函数
  • 所以通常将基类的析构函数声明为虚函数

题目:马戏团

/*
 * theater.cxx
 * 
 * 封装马戏团动物,需要表演
 * 封装狮子老虎大象
 */


#include <iostream>
using namespace std;

class Theater{
	public:
	virtual void show(){cout<<"start showing!\\n";}
};

class Lion: public Theater
{
	public:
	 void show(){cout<<"lion showing!\\n";}
};

class Tiger: public Theater
{
	public:
	 void show(){cout<<"Tiger showing!\\n";}
};

class Elephant: public Theater
{
	public:
	 void show(){cout<<"Elephant showing!\\n";}
};



int main(int argc, char **argv)
{
	Theater th;
	th.show();
	Lion lion;
	lion.show();
	Tiger tiger;
	tiger.show();
	return 0;
}


输出:

start showing!
lion showing!
Tiger showing!

也可以使用基类指针调用派生类的成员函数(使用指针实现多态)

int main(int argc, char **argv)
{
	
	Theater* th = new Theater;
	th->show();
	
	th = new Lion;
	th->show();
	
	th = new Tiger;
	th->show();
	
	th = new Elephant;
	th->show();
	
	return 0;
}

输出:

start showing!
lion showing!
Tiger showing!

也可以使用引用,但是没有指针灵活

int main(int argc, char **argv)
{
	Lion lion;
	Tiger tiger;
	
	Theater& th1 = lion;
	th1.show();
	
	Theater& th2 = tiger;
	th2.show();
	return 0;
}

如果一个类包含了虚函数,则在创建该类对象时会额外增加一个数组,数组中的每一个元素都是虚函数的入口地址。这个数组和对象分开存储,编译器在对象中安插了一个指针指向数组起始位置。这个数组就是虚函数表(vtable)

题目:角色扮演游戏

fight_res():使用基类引用访问派生类

/*
 * roleplay.cxx
 * 
 *  角色:名字,血量,攻击,防御。攻击方法,伤害=攻击-防御,血量为0则死亡不可再攻击
 * 法师类:添加法伤属性,此属性对伤害造成150%修正
 * 战士类:添加减伤属性,此属性对伤害造成75%修正
 * 对战接口,1对1,互殴至死
 */


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

class Role
{
	protected:
		string name;
		double HP;
		int ATK;
		int DEF;
		
	public:
		Role() :name(""),HP(0),ATK(0),DEF(0){}
		
		Role(string na, double hp, int atk, int def)
			:name(na),HP(hp),ATK(atk),DEF(def)
		{}
		
		inline string getname()const{return name;}
		inline double getHP()const{return HP;}
		inline int getATK()const{return ATK;}
		inline int getDEF()const{return DEF;}
		
		inline void setHP(double hp){HP=hp;}
		inline void setATK(int atk){ATK=atk;}
		inline void setDEF(int def){DEF=def;}
		
		bool if_dead(){
			return HP<=0;
		}
		
		virtual double getDamage(Role& role)
		{
			double damage = this->ATK - role.getDEF();
			return damage;
		}
		
		virtual void getHurt(double damage)
		{
			if(damage>=getHP()) setHP(0);
			else setHP(getHP()-damage);
			return;
		}
		
		virtual double attack( Role& role){
			double damage = getDamage(role);
			role.getHurt(damage);
			return damage;
		}
};

class Mage :  public Role
{
	private:
		double spell; //魔法加成
	public:
		Mage() :Role() {}
	
		Mage(string na, double hp=100, int atk=50, int def=5, double sp=1.5)
			:Role(na, hp, atk, def),spell(sp)
		{}
	
		 double getDamage(Role& role)
		{
			double damage = this->spell * (this->ATK - role.getDEF());
			return damage;
		}
};

class Worrior :  public Role
{
	private:
		double redu; //减伤
	public:
		Worrior() :Role() {}
	
		Worrior(string na, double hp=100, int atk=20, int def=10, double re=0.75)
			:Role(na, hp, atk, def),redu(re)
		{}
		
		virtual void getHurt(double damage)
		{
			damage *= redu ;
			if(damage>=getHP()) setHP(0);
			else setHP(getHP()-damage);
			return;
		}
};

void fight_res(Role& role1, Role& role2)
{
	cout<<"fight start!\\n";
	while(1){
		if(role1.getATK()<role2.getDEF()){cout<<"Destined die!\\n";return;}
		cout<< role1.getname() <<" hurt "<< role2.getname();
		cout<<" by "<< role1.attack(role2) <<" points blood \\n";
		cout<< role2.getname() <<" left "<< role2.getHP() <<endl;
		
		if(role1.if_dead()){
			cout<< role1.getname() <<" is dead.\\n";
			break;
		}
		if(role2.if_dead()){
			cout<< role2.getname() <<" is dead.\\n";
			break;
		}
	}
}

int main(int argc, char **argv)
{
	Mage mage("mage");
	Worrior wor("wor");
	fight_res(mage,wor);
	return 0;
}


输出:

fight start!
wor hurt mage by 15 points blood 
mage left 85
wor hurt mage by 15 points blood 
mage left 70
wor hurt mage by 15 points blood 
mage left 55
wor hurt mage by 15 points blood 
mage left 40
wor hurt mage by 15 points blood 
mage left 25
wor hurt mage by 15 points blood 
mage left 10
wor hurt mage by 15 points blood 
mage left 0
mage is dead.


以上是关于C++学习_多态的主要内容,如果未能解决你的问题,请参考以下文章

C++学习摘要之四:虚函数和多态

学习攻略C++虚函数表及多态内部原理详解

java中封装,继承,多态,接口学习总结

c++学习笔记:多态

C++中的多态详解

学习 C++:多态性和切片