C++ 继承与多态(下)
2026/6/10 2:15:23 网站建设 项目流程

今天我们主要讲一下多态^-^

一、多态的定义

多态是面向对象三大特性之一,指父类引用指向子类实例,在程序运行阶段,调用同名成员方法时,会根据对象实际类型执行对应子类重写后的方法,实现一个接口、多种实现的效果。

可分为:

编译时多态(静态多态):比如函数重载,函数模板

运行时多态(动态多态):传不同对象产生不同的行为

举例

二、多态的构成条件

1.存在继承关系:子类公有继承父类

2.子类重写父类的虚函数:函数名、参数、返回值完全一致

3.父类中函数声明为virtual(虚函数)(虚函数请看下文)

4.使用父类指针 / 引用指向子类对象

三、虚函数

1.定义

类成员函数前加virtual 修饰(父类子类都要加:父类一定要加,子类可不加但不规范),那么这个成员函数被称为虚函数。

2.虚函数的重写/覆盖

重写/覆盖 (Override):子类重新实现父类中同名、同参数列表、同返回值的虚函数,覆盖父类原有实现,是实现 C++ 运行时多态的前提

条件(三同):派生类中有一个和基类完全相同(函数名,参数,返回值都相同)的虚函数。

3.协变(了解一下)

定义:重写虚函数时,返回值允许不一样: 父类虚函数返回基类指针 / 引用,子类重写版本可以返回派生类指针 / 引用,这种合法的返回值变化就叫协变

注意:返回的基类对象的指针/引用不一定非得是自己的。

仅限:指针 / 引用,普通对象不支持协变。

4.析构函数的重写

基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写。(编译器将他们都处理成destructor():编译器编译时,会将所有析构函数抽象为统一的析构入口,纳入虚函数表管理;)

5.override和final

1.override(重写校验)

显式声明该函数是用来重写父类虚函数,让编译器做语法检查,防止手写失误。

注意:只能加在子类重写的虚函数后面。

校验规则:不满足直接编译报错。

2.final

2.1 修饰虚函数:禁止后续子类重写

final 加在虚函数末尾,表示:本函数到此为止,后代子类不能再重写。

2.2 修饰:禁止该类被继承

final 写在类名后,整个类无法作为基类派生子类。

四、对比重载/重写(覆盖)/隐藏

五、纯虚函数和抽象类

1.纯虚函数

在虚函数后写上“ = 0 ”,只声明,不需要定义实现(因为无意义)

2.抽象类

包含纯虚函数的类叫抽象类,抽象类不能实例化出对象。

如果派生类继承后不重写纯虚函数,那么派生类也是抽象类。

某种程度上强制了派生类重写虚函数(否则实例不出对象)。

六、虚函数表指针

只要类包含虚函数,编译器会自动给这个类的每个对象在内存最开头加一个隐藏的指针 vptr。

存在于含有虚函数的类的对象中,是对象内存里第一个成员,本质是一个指针变量,指向该类对应的虚函数表。

七、动态绑定&静态绑定

动态绑定:

满足多态条件的函数调用是在运行时绑定,也就是在运行时到指定对象的虚函数表中找到调用的函数的地址。

静态绑定:

对不满足多态条件的函数调用是在编译时绑定,也就是编译时确定调用函数的地址。

八、虚函数表

每个有虚函数的类,全局只生成一张静态表,里面存着虚函数的地址。

1. 基类对象在虚函数表中存放所有虚函数的地址。

2.派生类有两部分构成,继承下来的基类中有虚表指针,自己就不会再生成虚表指针(和父类不是同一个)。

3.派生类中重写基类的虚函数,地址覆盖。对应虚函数地址也要覆盖。

4.虚函数表本质是一个存虚函数指针的指针数组,一般这个数组后放了0x00000000标记(各个编译器不同,vs是这样的,gcc则不是)。

5.虚函数存在代码段,它的指针在虚表中,虚函数表在vs下也存在代码段。

如果有错误麻烦大佬们指正,非常感谢 orz

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询