基类指针、虚纯虚函数、多态性、虚析构

多态

基类指针

//  父类指针可以 new 一个子类对象
Human *pman = new Man();
Human *pwman = new Wonan();

抛出问题:父类指针没有办法调用子类的成员函数,那么你为什么还让父类指针 new 一个子类对象呢?
下面与虚函数搭配

虚函数(动态绑定)

我们只定义一个对象指针,就能够调用父类,以及各个子类的同名函数? ===> 有,这个对象指针,它的类型必须是父类类型
对这个函数有要求:

  1. 父类中,函数声明之前要加 virtual 声明成虚函数
  2. 一旦某个函数(在基类)被声明成了虚函数,那么所有派生类(子类)中同名函数都是虚函数
Human *phuman = new Men();
phuman->eat();  //  调用的是 Men 类的 eat 函数
delete phuman;  //  new 的对象使用完之后要 delete,防止内存泄漏

phuman = new Women();
phuman->eat();  //  调用的是 Women 类的 eat 函数
delete phuman;

phuman = new Human();
phuman->eat();  //  调用的是 Human 类的 eat 函数
delete phuman;

override

注意:为了避免你在子类中写错虚函数,在 C++11 中,你可以在函数声明这里增加一个 override 关键字
这个关键字在 "子类" 中,而且是子虚函数专用

override就是用来说明派生类中的虚函数,你用了这个关键字之后,编译器就会认为你这个 函数就是覆盖了父类中的同名函数。
只有虚函数才存在子类可以覆盖父类中同名函数的问题,那么编译器就会在父类中找同名同参的虚函数,如果没找到,编译器就会报错、

final

final 也是虚函数专用,是用在父类,如果我们在父类的函数声明中加了 final,那么任何尝试覆盖该函数的操作都将引发错误。

virtual void eat() final;

多态性

系统内部实际上是要查一个虚函数表,找到 eat() 的入口地址,从而调用父类或者子类的 eat() 函数,这就是运行时期的多态性

纯虚函数【类似 Java 中的接口 interface】===> 函数原型后增加 = 0

纯虚函数:没有函数体,只有一个函数声明

virtual void eat() = 0;

是在基类中声明的虚函数,但是它在基类中没有定义,但是要求任何派生类都要定义该虚函数自己的实现方法
注意:一旦一个类中有纯虚函数了,那么你就不能生成这个类的对象了【Java 中 interface 不能生成对象】
抽象类不能用来生成对象,主要目的用来统一管理子类对象

基类的析构函数一般写成虚函数(虚析构函数)

// 1. 声明一个 men 对象
Men men;
// 2. 写法2:使用 new
Men *pmen = new Men();
delete pmen;  //  自己 new 的对象,必须使用 delete 调用析构函数


有一个问题

Human *phuman = new Men();  //  父类指针指向 子类对象
delete phuman;  //  没有执行子类的析构函数

结论:用基类指针 new子类的对象,在 delete 的时候,系统不会调用派生类的析构函数,这肯定就有问题了

解决方式:

  1. 父类的析构函数写成虚函数
  2. 继承时候使用 public
posted @ 2024-10-26 00:56  爱新觉罗LQ  阅读(4)  评论(0编辑  收藏  举报