本篇文章是对B站上一个课程的笔记 https://www.bilibili.com/video/BV1LK411s7ES?from=search&seid=13723858519383902190
Question1:虚函数引入后类会发生什么变化?
对于一个空类,其sizeof值是1
对空类加入两个普通成员函数,其sizeof仍然是1(只有成员变量会占用内存空间,普通成员函数并不会占用空间)
继续加入一个虚函数,sizeof值变成了4!!
这是因为,如果类中存在虚函数,则编译器就会在类中插入一个看不见的成员变量,也就是虚函数表指针 *vptr,该成员变量占4个字节。
Question2:虚函数表的生成时机和生成原因
当一个类中有至少一个虚函数时,在编译期间,编译器会为该类生成一个虚函数表,这个虚函数表会从始至终伴随这个类,经过编译链接保存到可执行文件中。
Question3:虚函数表与虚函数表指针的关系
对有虚函数的类,编译器会在编译期间,在该类的构造函数中默默添加一个为虚函数表指针赋值的语句。在创建对象时,会调用构造函数,此时就会使得虚函数指针指向虚函数表。
Question4:类对象在内存中的布局
在类A中有两个普通的成员函数,两个普通虚函数,一个虚析构函数,和两个成员变量。
当生成类A对象时,在内存中的布局如下: 占用内存空间的只有虚函数表指针以及两个成员变量,虚函数表指针指向虚函数表,由于该类有三个虚函数,所以虚函数表中的三个地址分别指向三个虚函数,两个普通成员函数属于类的成员,但是不在类的对象中占有内存。
Question5:虚函数的工作原理和多态性的实现
多态必须存在虚函数,没有虚函数绝不可能存在多态。
实现多态必须有以下三个条件
1.程序中有父类和子类的继承关系,父类指针必须含有虚函数,子类中也必须重写父类中的虚函数。
2.用父类的指针指向子类的对象/用父类的引用绑定子类的对象。
3.用这个父类指着调用子类中重写的虚函数。
该类中有一个父类Base,一个子类Derive,子类中重写了g函数,内存结构如下图所示:
父类和子类都有一个自己的虚函数表指针,指向自己的虚函数表。父类和子类的虚函数表中都有三个地址,对于普通的成员函数,虚函数表中的地址项相同,对于重写的虚函数会用新的函数地址进行覆盖。因此在用父类的指针指向子类对象时,是通过子类对象的虚函数表指针找到子类的虚函数表,从而查询到虚函数的地址。