c++------多态

多态

多态的基本概念

  • 多态 c++面向对象三大特性之一
  • 多态分为两类:
  • 静态多态 : 函数重载和 运算符重载 属于静态多态 ,复用函数名
  • 动态多态 : 派生类 和 虚函数 实现运行时多态
  • 两者区别:
  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 多态多态的函数地址晚绑定 - 运行阶段确定函数地址
class animal    **//此时占一个字节**
{
public :
	void speak()   
	{
		cout << "动物说话" << endl; 
	}	 
} ; 

//猫
class cat :public animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl; 
	} 
} ;

 //执行说话的函数
 //地址早绑定 显示  动物在说话 而非猫在说话
 void dospeak(animal &animal)  //animal &animal = cat 
 {
 	animal.speak(); 
 } 
  
void test01()
{
	cat cat;
	dospeak(cat); 
} 

如果想执行 猫在说话 ,那么这个地址不能提前绑定,需要在运行阶段绑定 改为如下

class animal   **//此时占4个字节  一个指针大小**
{
public :
	//虚函数 
	virtual void speak()
	{
		cout << "动物说话" << endl; 
	}	 
} ; 

//狗
class dog :public animal 
{
public:
	void speak()
	{
		cout << "小狗在说话" << endl; 
	} 
} ;
void test01()
{
	//cat cat;
	//dospeak(cat); 
	
	dog dog;
	dospeak(dog); 
} 

动态多态满足条件:

1.有继承关系
2.子类需要重写父类中的虚函数 virtual
重写:函数返回值类型 函数名 参数列表 需要完全相同

动态多态使用:

父类的指针或者引用指向子类对象
Animal &animal = cat;

多态案例1 计算机类

案例描述:
分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算机类

//普通实现
class calculator
{
public:
	int getresult(string oper)
	{
		if (oper == "+")
		{
			return num1 + num2; 
		} 
		else if (oper == "-")
		{
			return num1 - num2; 
		} 
		else if (oper == "*")
		{
			return num1 * num2; 
		} 
		//如果想扩展新的功能,需要修改源码
		//在真实开发中,提倡 开闭原则 即,对修改进行关闭,对扩展进行开发
	int num1;
	int num2; 
		 
}; 

void test01()
{//创建计算器对象 
	calculator c; 
	c.num1 = 10;
	c.num2 = 10; 
	cout <<  c.num1 << "+" << c.num2 << " = " << c.getresult("+")  << endl; 
	cout <<  c.num1 << "-" << c.num2 << " = " << c.getresult("-")  << endl; 
	cout <<  c.num1 << "*" << c.num2 << " = " << c.getresult("*")  << endl; 
	
} 

多态实现

// 利用多态实现计算器

//实现计算器抽象类
class abstractcalculator
{
public :
	virtual int getresult()
	{
		return 0; 
	} 
	
	int num1;
	int num2; 
} ; 

//加法计算器类
class addcalculator :public adstractcalculator 
{
public :
	int getresult
	{
		return num1 + num2; 
	}	
} ; 

//减法计算器类
class subcalculator :public adstractcalculator 
{
public :
	int getresult
	{
		return num1 - num2; 
	}	
} ; 

//乘法计算器类
class mulcalculator :public adstractcalculator 
{
public :
	int getresult
	{
		return num1 * num2; 
	}	
} ; 

void test02
{
	//多态使用条件
	//父类指针或者引用指向子类对象
	
	//加法
	adstractcalculator * abc =  new addcalculatoro;
	abc->num1 = 100;
	abc->num2 = 100;
	cout << abc-> num1 << "+" << abc->num2 << "=" << abc->getresult << endl; 
	// 记得销毁
	delete abc;
	
	//减法
	abc = new subcalculator; 
	cout << abc-> num1 << "-" << abc->num2 << "=" << abc->getresult << endl; 
	// 记得销毁
	delete abc;
	
	//乘法
	abc = new mulcalculator; 
	cout << abc-> num1 << "*" << abc->num2 << "=" << abc->getresult << endl; 
	// 记得销毁
	delete abc;
	
} 

好处:
1.组织结构清晰 2.可读性强 3.对于前期和后期的扩展,可维护性高

纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为 纯虚函数

纯虚函数语法:

virtual 返回值类型 函数名 (参数列表) = 0;
  • 当类中有了纯虚函数,这个类也称为抽象类

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类.
//纯虚函数和抽象类
class base
{
public:
	//纯虚函数
	virtual void func() = 0; 
}; 

class son:public base   
{
public:
	virtual void func() {};   // 子类必须重写父类 中纯虚函数 ,哪怕是空 
	 
}; 

void test01()
{
	//1.无法实例化对象
	//base b;        错误
	// new base;     错误
	
	
	son s;  //子类必须重写父类 中纯虚函数 ,否则无法实例化 
	base *base = new son;
	base->func(); 
	
	 
} 

多态的目的就是 通过一个父类指针,由于创建对象不同,可以调用多种形态的函数

案例2 制作饮料

利用多态技术实现,提供抽象制作饮料基类.提供子类制作咖啡和茶叶

class adstractdrinking
{
public:
	//煮水
	virtual void boil() = 0;
	
	//冲泡 
	virtual void brew() = 0;
	
	//倒杯 
	virtual void pour() = 0;
	
	//加料
	virtual void putsomething() = 0; 
	
	//制作饮料
	void makedrinking()
	{
		boil(); 
		brew();
		pour();
		putsomething(); 
	} 
} ;

//制作咖啡
class coffee :public  adstractdrinking
{
public :
	//煮水
	virtual void boil()
	{
		cout << "农夫山泉" << endl; 
	} 
	
	//冲泡 
	virtual void brew()
	{
		cout << "冲泡咖啡"  << endl; 
	} 
	
	//倒杯 
	virtual void pour()
	{
		cout << "倒入杯中"  << endl; 
	} 
	
	//加料
	virtual void putsomething()
	{
		cout << "加入方糖"  << endl; 
	} 
	 
}; 


//制作茶叶
class teacoffee :public  adstractdrinking
{
public :
	//煮水
	virtual void boil()
	{
		cout << "矿泉水" << endl; 
	} 
	
	//冲泡 
	virtual void brew()
	{
		cout << "冲泡茶叶"  << endl; 
	} 
	
	//倒杯 
	virtual void pour()
	{
		cout << "倒入杯中"  << endl; 
	} 
	
	//加料
	virtual void putsomething()
	{
		cout << "加入枸杞"  << endl; 
	} 
	 
}; 

//制作 
void dowork(adstractdrinking *abc)  //adstractdrinking * abc = new coffee /tea 
{
	abc-> makedrink();  // 同一个接口 
	delete abc;
	
	 
} 

void test01 ()
{
	//咖啡
	dowork(new coffee) ; 
	
	//茶叶
	dowork(new tea) ; 
	 
} 

int main()
{
	test01(); 
} 
 

虚析构和纯虚函数

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码.
解决方式: 将父类中析构函数改为虚函数/纯虚函数

  • 虚函数和纯虚函数共性 :

  • 可以解决父类指针释放子类对象

  • 都需要有具有的函数实现

  • 虚析构和纯虚析构区别:

  • 如果是纯虚函数,该类属于抽象类,无法实例化对象

  • 虚析构语法:.

virtual ~类名(){}

*纯虚析构语法

virtual ~类名()=0;
类名::~类名(){}

class animal
{
public:
	
	animal()
	{
		cout << "animal构造函数"   << endl;
	} 
	~animal()
	{
		cout << "animal析构函数"   << endl;
	} 
	
	
	//纯虚函数
	virtual void speak() = 0; 
} ;

class cat :public animal 
{
public :
	
	cat(string n)
	{
		cout << "cat构造函数"   << endl;
		name = new string (n); 
	} 
	
	
	virtual void speak()
	{
		cout << *name << "小猫在说话" << endl; 
	} 
	
	~cat()
	{
		if(name != null)
		{
			cout << "cat析构函数"   << endl;
			delete name;
			name = null; 
		} 
	} 
	
	string *name; 
} ;


void test01()
{
	animal *animal = new cat("tom");
	animal->speak();
//父类指针在析构时候 不会调用子类中析构函数,导致子类如果有堆属性,会出现内存泄漏
	delete animal; 
	 
} 
 

此时运行结果:
animal构造函数
cat构造函数
tom在说话
animal析构函数调用

cat析构函数呢???
父类指针在析构时候 不会调用子类中析构函数,导致子类如果有堆属性,会出现内存泄漏

解决方法: 父类析构改为虚析构

virtual ~animal()
	{
		cout << "animal析构函数"   << endl;
	} 
//或者用纯虚析构   声明 + 实现,
class animal
{
public:
	
	animal()
	{
		cout << "animal构造函数"   << endl;
	} 
	//纯虚析构
	virtual ~animal = 0;
	
	//纯虚函数
	virtual void speak() = 0; 
} ;

animal ::~animal()
{
		cout << "animal纯虚析构函数"   << endl;
} 


此时运行结果:
animal构造函数
cat构造函数
tom在说话
cat析构函数
animal(纯)析构函数调用

利用虚析构可以解决 父类指针释放子类对象时不干净的问题

总结:
1.虚析构或者纯虚析构就是用来解决父类指针释放子类对象
2.如果子类中没堆区数据,可以不写为虚析构 纯虚析构
3.拥有纯虚析构的类也属于抽象类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值