背景:用于实现多态
静态多态:通过函数重载 动态多态:运行时多态,父类指针的指向,如果指向的是基类就去基类的虚函数表找相关函数接口,如果指向子类,就去子类的虚函数表找
虚函数表的创建时机:
a. 什么时候生成
在编译器编译的时候生成的,发现virtual关键字修饰的函数时生成
b. 存放在哪里?可执行程序(磁盘),运行时(内存)?
.bss:存放未初始化或者初始化为0的全局变量,静态变量 .data:初始化的全局变量,静态变量 .rodata:只读数据段(常量和只读变量),虚函数表 .text:代码段(具体的函数实现,包括虚函数的实现)
程序加载时的映射关系: 虚拟内存:32位(1G+3G) 64位(128T+128T) 内核空间 栈区 文件映射区 堆区 数据区(静态存储区):.bss .data 代码区 .rodata .text
c. 虚函数表与虚函数指针的关系
编译时,并不知道每个类会创建多少个对象,所以虚函数表是与类相关的,一个类对应一个虚函数表 虚函数表指针:每个类创建了很多对象,每个对象拥有的是虚函数表指针 虚函数表指针指向虚函数表 一个对象的前4/8个字节存储的是虚函数指针(vtptr) 不同对象的虚函数表指针不一样,但是指向的地址是一样的。 (浅拷贝和深拷贝,浅拷贝时两个对象的虚函数指针相同,如果一个对象释放了,会导致另一个对象的虚函数表指针丢失) 显式定义拷贝构造和重载=,深拷贝
d. 虚函数表指针的创建时机(构造时赋值)
1、类对象构造的时候,会把类的虚函数表地址赋值给vptr 2、没有构造函数时,编译器会生成默认的构造函数 3、继承时:如果没有重写,就会复制父类的,发生重写时,就将重写后的虚函数地址进行替换 a.调用基类的构造函数,把基类A的虚函数表地址赋值给 vptr(新子类) b.调用子类的构造函数,把子类B的虚函数表指针赋值给 vptr(新子类) 赋值两次