今天我们主要讲一下多态^-^一、多态的定义多态是面向对象三大特性之一指父类引用指向子类实例在程序运行阶段调用同名成员方法时会根据对象实际类型执行对应子类重写后的方法实现一个接口、多种实现的效果。可分为编译时多态静态多态比如函数重载函数模板运行时多态动态多态传不同对象产生不同的行为举例二、多态的构成条件1.存在继承关系子类公有继承父类2.子类重写父类的虚函数函数名、参数、返回值完全一致3.父类中函数声明为virtual虚函数虚函数请看下文4.使用父类指针 / 引用指向子类对象三、虚函数1.定义类成员函数前加virtual 修饰父类子类都要加父类一定要加子类可不加但不规范那么这个成员函数被称为虚函数。2.虚函数的重写/覆盖重写/覆盖 Override子类重新实现父类中同名、同参数列表、同返回值的虚函数覆盖父类原有实现是实现 C 运行时多态的前提。条件三同派生类中有一个和基类完全相同函数名参数返回值都相同的虚函数。3.协变了解一下定义重写虚函数时返回值允许不一样 父类虚函数返回基类指针 / 引用子类重写版本可以返回派生类指针 / 引用这种合法的返回值变化就叫协变。注意返回的基类对象的指针/引用不一定非得是自己的。仅限指针 / 引用普通对象不支持协变。4.析构函数的重写基类的析构函数为虚函数此时派生类析构函数只要定义无论是否加virtual关键字都与基类的析构函数构成重写。编译器将他们都处理成destructor编译器编译时会将所有析构函数抽象为统一的析构入口纳入虚函数表管理5.override和final1.override重写校验显式声明该函数是用来重写父类虚函数让编译器做语法检查防止手写失误。注意只能加在子类重写的虚函数后面。校验规则不满足直接编译报错。2.final2.1 修饰虚函数禁止后续子类重写final 加在虚函数末尾表示本函数到此为止后代子类不能再重写。2.2 修饰类禁止该类被继承final 写在类名后整个类无法作为基类派生子类。四、对比重载/重写覆盖/隐藏五、纯虚函数和抽象类1.纯虚函数在虚函数后写上“ 0 ”只声明不需要定义实现因为无意义2.抽象类包含纯虚函数的类叫抽象类抽象类不能实例化出对象。如果派生类继承后不重写纯虚函数那么派生类也是抽象类。某种程度上强制了派生类重写虚函数否则实例不出对象。六、虚函数表指针只要类包含虚函数编译器会自动给这个类的每个对象在内存最开头加一个隐藏的指针 vptr。存在于含有虚函数的类的对象中是对象内存里第一个成员本质是一个指针变量指向该类对应的虚函数表。七、动态绑定静态绑定动态绑定满足多态条件的函数调用是在运行时绑定也就是在运行时到指定对象的虚函数表中找到调用的函数的地址。静态绑定对不满足多态条件的函数调用是在编译时绑定也就是编译时确定调用函数的地址。八、虚函数表每个有虚函数的类全局只生成一张静态表里面存着虚函数的地址。1. 基类对象在虚函数表中存放所有虚函数的地址。2.派生类有两部分构成继承下来的基类中有虚表指针自己就不会再生成虚表指针和父类不是同一个。3.派生类中重写基类的虚函数地址覆盖。对应虚函数地址也要覆盖。4.虚函数表本质是一个存虚函数指针的指针数组一般这个数组后放了0x00000000标记各个编译器不同vs是这样的gcc则不是。5.虚函数存在代码段它的指针在虚表中虚函数表在vs下也存在代码段。如果有错误麻烦大佬们指正非常感谢 orz