面向对象编程(37)

多态的实现

多态的特性主要体现在“一种接口,多种实现”,通过统一的接口定义,来匹配各种特殊的处理方式。它的应用范围很广,是面向对象编程非常重要的思想。

条件:继承、重写、父类指针指向派生类

重写(Override)与重载(Overload)的区别:重写是派生类对父类函数的多态性表现,也就是派生类具有特殊的父类行为;重载是同一个类(或者全局函数等)中同名函数通过形参不同实现匹配。最大区别可以理解为:重写看对象,重载看形参。

多态实现:

#include<iostream>
using namespace std;
class person
{
public:
  virtual  void show()  //加virtual表明实现多态,否则不会被派生类改写。
  {
	  cout<<"person show"<<endl;
  }
};

class student:public person
{
public:
  void show() //这是重写,用来覆盖父类的函数,实现多态
  {
	  cout<<"student show"<<endl;
  }
  void show(int c)// 这是重载,参数不同
  {
	  cout<<c<<": student show"<<endl;
  }
};
int main()
{
	person *lp,p;
	student s,*lq;	
	lp=&s;  //父类的指针指向派生类是可以,可以理解成把s 这个student 看成 person 。	        
	lq=(student *)&p;//同时,派生类指针特殊情况下可以指向父类对象。
	                 //强制转换符合语法,但是这里显然不合理,除非,p确实是一个student对象
	lp->show(); //父类中函数如果不加virtual 还会调用父类的show函数
	            //加virtual 则实现多态,父类指针指向不同的派生类,实现特殊功能。
	lq->show();//只能调用父类的show
	return 0;
}

1、virtual 称为虚函数,实现多态要加上,否则指向派生类对象的父类指针不能完成多态;

2、父类指针指向派生类需要好好理解,派生类指针指向父类对象在某些应用场景会出现;

3、派生类重写的虚函数会继承虚函数的特征,上例中student的show函数自动带有虚函数的特征,可以被它的子类重写。

虚函数

多态里面最重要理解virtual

class person
{
public: 
  virtual  void f(){}  
  virtual void g(){};
  void k(){};
};
class student:public person
{
public: 
  void f() {}
  void t(){};
};

先画父类和派生的实例示意图:

1、父类有虚函数,则父类及派生的对象在实例化(定义出对象)的时候,都会给每个对象添加一个虚函数表的指针,并且指向该类的虚函数表;

2、父类的指针指向派生类对象,该指针调用虚函数的时候,找到的实例是派生类,因此使用派生类的虚函数表指针去加载相应的函数,从而实现多态。如上例中:student 改写了f(),继承了g();

3、构造函数不能写能虚函数,虚函数是在构造出对象(实例化)后 “补上” 的虚函数调用表,对象都没有虚函数表指针不存在。 对象需要构造函数才能产生,构造函数则需要对象生成后加载虚函数表;

4、析构函数可以写成虚函数(建议使用),可能在new 和 delete中出现问题:

     person *lp=new student();    
      delete lp;

     删除堆中new出的对象的时候,如果该对象的析构函数不是虚函数,则只调用父类(person)的析构函数;如果把父类的析构函数写成虚函数,则首先调用派生类(student)的析构函数,再调用父类的析构函数(与栈中回收对象相同)。因此,推荐父类的析构函数(派生类自动继承虚函数特征)写成虚函数。

纯虚函数和抽象类

父类中不能实现虚函数功能(空的函数体也不行)情况下,可以定义成纯虚函数:

virtual  函数类型   函数名(形参列表) =  0;

也就是该虚函数加上 “ = 0 ” 的标记。

类中定义了纯虚函数,则该类称为抽象类,不能实例化(可以定义指针,这要区别)

继承于抽象类的派生类,如果不重写(实现)父类的纯虚函数,派生类也是一个抽象类。

纯虚函数应该属于C++的 “接口编程思想”,要使用抽象类的功能,不仅仅继承于抽象类,还必须实现指定的纯虚函数,其实就是接口编程是思想(JAVA的事件侦听器)

#include<iostream>
using namespace std;
class person
{
public: 
  virtual  void f(){}  
  virtual void g()=0;
  void k(){};
};
class student:public person
{
public:  
  void g(){};//需改写纯虚函数,否则也是抽象类
  void f() {}
  void t(){};
};
int main()
{	
	//person y;   错误,抽象类不能实例化
	//person *q =new person();  错误,抽象类不能实例化
	student x;
	person *p =new student();//正确,定义指针,new 的是派生类对象
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值