01
—
面向对象编程的特点
抽象、封装、继承、多态
02
—
什么是多态 ?
在程序中同一符号在不同情况下具有不同解释的现象称为多态
现实世界中的多态现象:
1)变色眼镜:阳光下—镜片颜色变深;室内—镜片颜色变浅。
2)猫眼瞳孔:光线充足地方——瞳孔变细变窄;晚上半夜——瞳孔放大、夜视能力变强。
编程中的多态
3)同一个类中,对应相同的函数名,却执行不同的函数体,即函数重载,属于编译时的多态。
4)派生类中,与基类同名、同参数、同返回类型的函数的不同行为,属于运行时的多态。
5)运算符重载
也就是说,编程中的多态,大体上可以分为编译时多态和运行时多态。编译时多态主要是通过重载机制完成,运行时多态主要通过虚函数实现。
多态机制可以简单地概括为一个接口,多种方法。
03
—
多态的作用
把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
04
—
C++如何实现多态 ?
只有采用指向基类对象的指针或引用来调用虚函数时,才会按动态联编的方式来调用。
示例代码:
# include using namespace std;class Shape {public: virtual void print() { cout << "in Shape" << endl; }};class Rectangle:public Shape { void print() { cout << "in Rectangle" << endl; }};class Circle:public Shape { void print() { cout << "in Circle" << endl; }};int main() { Shape* p = new Rectangle(); p->print(); Shape* q = new Circle(); q->print(); return 0;}/**程序输出:in Rectanglein Circle*/
05
—
虚函数与纯虚函数的区别
1. 虚函数:如果一个类中声明了虚函数,这个函数是实现的,他的作用是为了能让这个函数在他的子类里面能被覆盖,这样就可以实现动态多态。
2. 纯虚函数:只是一个接口(interface),是个函数的声明而已,留在子类中实现。
3. 虚函数在子类中可以不覆盖
4. 纯虚函数必须在子类中实现
5. 虚函数的类用作”实现继承“,即继承接口的同时也继承了父类的实现。
6. 纯虚函数用于”介面继承“,即纯虚函数关注的是接口的统一性,实现由子类完成
7. 带纯虚函数的类叫做虚基类,这种类不能直接生成对象。
06
—
什么函数可以被定义为虚函数 ?
静态成员函数、内联函数、友元函数和构造函数都不能说明为虚函数。但析构函数可以是虚函数。如果基类的析构函数为虚析构函数,则派生类的析构函数也是虚析构函数。
【面试题】为什么构造函数不可以作为虚函数?
最佳回答:构造一个对象的时候,必须知道对象的实际类型,但虚函数行为是在运行期间确定实际类型的。
补充回答:虚函数的执行依赖于虚函数表(一个指针数组,每一项指向一个virtual function的起始地址)。虚函数表在构造函数中初始化vptr(vptr指向虚函数表头)。但在构造对象期间,vptr还没被初始化,构造过程无法进行。
一般来说,确定一个函数是否要声明为虚函数,可以参考下面两个依据:
1. 首先,成员函数所在的类是否是基类,其次,该成员函数在类的继承后是否将被改动,如果希望改变其功能,一般将它声明为虚函数。
2. 考虑对成员函数的调用是通过对象名还是通过基类指针或引用去访问,如果是通过基类指针或引用去访问的,则应当声明为虚函数。
07
—
虚析构函数的作用
在基类设置虚析构函数,目的是在使用delete释放一个基类指针指向的派生类对象时采用动态联编的方式选择正确的派生类析构函数。
08
—
函数重载/重写/重定义的区别
函数重载:重载函数通常用来命名一组功能相似的函数
1. 函数要在相同的类域
2. 函数的名字要相同
3. 函数的参数列表或返回值不同
函数覆盖:覆盖是指派生类函数覆盖基类函数
1. 函数是要在不同的类域
2. 两个函数的名称相同
3. 基类函数必须是虚函数
3. 两个函数的参数相同
函数隐藏:指派生类的函数屏蔽了与其同名的基类函数
1. 两个函数在不同的类域
2. 函数名称相同
3. 函数参数不同
4. 如果派生类函数与基类函数参数相同,但是在基类函数中没有virtual关键字,发生函数隐藏
09
—
Java中的多态
戳原文链接:《深入分析java中的多态(从jvm角度分析)》
10
—
配套视频
浙江大学 - 翁恺《Java程序设计》
链接:https://www.bilibili.com/video/BV1DJ411B7cG?p=75