在学习了继承和多态后,本人有以下容易造成混乱的点以及问题:
1.区分虚表和虚基表
虚表即虚函数表,存储的是虚函数的地址。另外:虚表是在编译阶段就生成的,一般存在于常量区(代码段)。
虚基表是是存储偏移量的。
注意要区分好:虚表存储的是虚函数的地址!!!而虚函数,是存在代码段中的。
2.区分虚表和虚表指针生成阶段
虚表是在编译阶段就生成的了,而虚表指针是在构造函数初始化列表阶段初始化的。这也侧面回答了下一个问题。
3.构造函可以是虚函数吗?
不行的,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。
4.区分切片和派生类虚表的生成
先来说派生类生成虚表的步骤:
①先是继承了基类的虚表,是把基类的虚表拷贝下来了。
②然后根据重写的虚函数,对虚表进行覆盖。
③最后是把自个类中的虚函数的地址也写进虚表中。
也就是说,派生类的虚表一开始是对基类的虚表的一个拷贝,后面才将其“本土化”。
切片:
我们都知道,多态的的条件是虚函数的重写和必须通过基类的指针或者引用调用虚函数。。那么为什么一定是需要基类的指针或引用呢?
先来看看不用指针或引用,也就是使用基类对象来调用虚函数。当传入的是派生类的对象,然后进行切片,此时我们假设基类对象对派生类对象切片的时候,不仅把属于自己的那一部分拷贝了过去, 还把派生类的虚表也拷贝了过去!如果后面需要基类的虚表的话就找不到了,这也就乱套了。因此,事实上,基类对象对派生类对象切片的时候,不会把派生类的虚表也拷贝过去,切片后将派生类中属于基类的一部分拷贝过去后,此时基类的虚表还是原本的虚表!基类原本的虚表里面都没有派生类重写的虚函数的地址,还要怎么构成多态?
因此,简单的总结就是:派生类对象赋值给基类对象,切片会把派生类中包含的基类成员变量的值拷贝过去,但是派生类的虚表不会给拷贝过去,则函数中这个基类对象的虚表是基类的,所以无法实现多态。而指针或者引用是直接指向派生类对象,不会进行拷贝赋值,这样虚函数表是派生类的虚函数表,故能实现多态。
5.inline函数可以是虚函数吗?
内联函数可以写成虚函数,不过写出虚函数后,这个内联函数就不是内联函数了。
6.静态成员可以是虚函数吗?
不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。
7.析构函数可以虚函数吗?
基类的析构函数最好是虚函数。因为有时候我们难免会用基类创建对象,而这个基类的对象指向的是派生类的,基类的析构函数是虚函数的话,可以准确地调用派生类的析构函数。
8.对象访问普通函数快还是虚函数更快?
首先如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。
9.什么是抽象类?抽象类的作用?
一个类中的虚函数如果是纯虚函数的话,那么这个类便是抽象类。另外,纯虚函数可以有函数实体,但是没必要。
抽象类的作用是强制重写虚函数。另外抽象类体现出了接口继承关系
大家如果还有什么问题需要补充的话可以评论告诉我哦!