直接继承
(原文链接:点击打开链接)
(1)无虚函数覆盖的单继承:
子类对象的内存布局:虚表指针、父类成员变量、子类成员变量
虚函数表的布局:父类的虚函数地址(按声明顺序)、子类自定义的虚函数的地址(按声明顺序)
(2)有虚函数覆盖的单继承
子类对象的内存布局:虚表指针、父类成员变量、子类成员变量
虚函数表的布局:子类已覆盖的虚函数的地址、父类中未被覆盖的虚函数的地址、子类自定义的虚函数的地址
(3)无虚函数覆盖的多继承
子类对象的内存布局:父类1的虚表指针、父类1的成员变量、父类2的虚表指针、父类2的成员变量
父类1虚函数表的布局:父类1的虚函数地址、子类自定义的虚函数的地址
父类2虚函数表的布局:父类2的虚函数地址
(4)有虚函数覆盖的多继承
子类对象的内存布局:父类1的虚表指针、父类1的成员变量、父类2的虚表指针、父类2的成员变量
父类1虚函数表的布局:子类已覆盖的虚函数的地址、父类中未被覆盖的虚函数的地址、子类自定义的虚函数的地址
父类2虚函数表的布局:子类已覆盖的虚函数的地址、父类中未被覆盖的虚函数的地址
总结:
直接继承的多继承中,继承了几个父类,就要维护几个虚函数表,并且为他们分配指针。
直接继承的多继承中,子类的自定义虚函数总是放在第一个父类的虚函数表的末尾。
直接继承的多继承中,如果发生菱形继承,那么子类对象的内存布局中不会做优化,比如说A派生B、C,D再多继承B、C,那么D类的对象会保存两个A类成员变量的副本。
但是虚继承的多继承中,如果发生菱形继承,那么
B对象的内存布局为:父类A的虚表指针、B自己的成员变量、父类A的成员变量
C对象的内存布局为:父类A的虚表指针、C自己的成员变量、父类A的成员变量
D对象的内存布局为:父类B的虚表指针、父类B的成员变量、
父类C的虚表指针、父类C的成员变量、D自己的成员变量、祖父类A的成员变量。
即只维护一个祖父类成员变量的副本,节省了空间。(引用链接:点击打开链接)