定义:
相同对象收到不同消息或不同对象收到相同消息时产生不同的动作。
静态多态(早绑定):
在编译之后,已经知道使用的是哪一个函数了
动态多态(晚绑定):
动态多态需要以封装和继承为基础。(起码要两个类)
想要实现多态的成员函数前添加virtual关键字,形成虚函数,子类的同名函数前可以不加,系统会自动加上,建议自己加上,看着明显。
↓
多态具体到语法中是指,使用父类指针指向子类对象,并
可以通过该指针调用子类的方法
虚析构函数:
要清楚使用它的地方:父类的构造函数中申请内存,即从堆中申请对象
销毁一个父类指针,只会执行父类的析构函数而不会执行子类的析构函数,会造成内存泄漏。
所以要使用虚析构函数,在析构函数前加virtual关键字
virtual在函数中的使用限制:
- 不能修饰普通函数(全局函数)
- 不能修饰静态成员函数:virtual static int getCount(),错误
- 不能修饰内联函数:inline virtual int eat( ),错误,系统会忽略inline关键字,使其成为一个虚函数
- 构造函数不能为虚函数
虚函数和虚析构函数的实现原理:
虚函数:
函数指针:指针指向函数→函数指针(指向一段二进制代码的开头)
父类中如果有虚函数,则会生成虚函数指针,指向虚函数表
函数的覆盖与隐藏:
覆盖:如果在子类中没有定义同名的虚函数,那么在子类的虚函数表中就会写上父类的相应的函数入口地址,反之则会覆盖其地址。
虚析构函数:
理论前提:执行完子类的析构函数就会执行父类的析构函数。
执行过程:子类的析构函数→父类的析构函数,如下图:
证明虚函数表指针存在:
概念:
- 对象的大小(类实例化出的对象当中,它的数据成员所占据的内存大小,不包括成员函数)
- 对象的地址
- 对象成员的地址
- 虚函数表指针(在有虚函数的情况下,实例化一个对象的时候,这个对象的第一块内存当中所存储的是一个指针,即虚函数表指针,占据大小为4)