C++学习之路(九):从菱形继承引入的对象模型
一、单继承
class A {int a;}; class B : public A {int b;};
普通的单继承关系,类的大小是由其虚表指针和非静态成员函数大小决定。故上述sizeof(A)的大小为4。
类B公有继承A,对象模型如下:
类A的非静态成员(4字节)
类B的非静态成员(4字节)
故类B的大小为8字节。
二、多继承
class A {int a;}; class B {int b;}; class C : public A, public B {int c;};
普通的多继承关系,这里和上述单继承类似。直接给出类C的对象模型如下:
类A的非静态成员(4字节)
类B的非静态成员(4字节)
类C的非静态成员(4字节)
故类C的大小为12字节。
三、含有虚函数的普通继承
(1)含有虚函数的类对象模型
C++中引入了虚函数,即多态的概念。如果一个类中存在虚函数,则该类对象在被实例化时,其首地址开始的4个字节存放着虚函数表指针(vptr),vptr指向了一个虚表(理解为结构体数组),数组中的每一个位置存放着虚函数的实际地址。(ps:一个类的大小与其非成员变量有关,所以如果一个仅包含虚函数的类,其大小只有一个虚表指针,即4字节)
class A { virtual void test(void); int a; };
故上述类A的大小为,一个vptr加上一个成员变量,为8字节。
(2)含有虚函数的普通单继承
class A { virtual void test(void); int a; }; class B : public A { int b; };
类B直接继承类A,由于类A中存在虚函数,所以类B对象中同样也会有vptr虚表指针,并指向一个虚表,用于重写test函数。类B的对象模型如下:
类B的vptr(4字节) -----> 指向了一个虚表
类A的非静态成员(4字节)
类B的非静态成员(4字节)
故类B的大小为12字节。(先虚表,然后是基类的成员,最后是子类的成员)
(3)含有虚函数的多继承
含有虚函数的多继承
class A
{
virtual void test_a(void){}
int a;
};
class B
{
virtual void test_b(void){}
int b;
};
class C : public A, public B {int c;};
类C的对象模型如下:
类A的vptr
A::a
类B的vptr
B::b
C::c
四、含有虚函数的类对象虚继承
class A { virtual void test(void); int a; }; class B : public virtual A {
void test(void);
virtual void test1(void);
int b; };
直接给出类B的对象模型如下:
类B的vptr(4字节) -----> 指向虚表,新增的虚函数放在自己的虚表
类B的非静态成员(4字节)
类A的vptr(4字节) ------> 指向虚表,重写的虚函数放在这个虚表。保存B::test()
类A的非静态成员(4字节)
故类B的大小为16字节。
五、菱形继承
所谓菱形继承,是一种较为特殊的多继承关系,融合了多继承与虚继承。如图:
结合代码如下:
class X {}; class Y : public virtual X {}; class Z : public virtual X {}; class A : public Y, public Z {};
如果通过sizeof输出上述四个类的大小,结果为:1,4,4,8。
(1)、空类的大小
C++定义一个类如果是一个空类,会被编译器默认插入一个char(1个字节),从而使得该类的两个对象在内存中可以有独一无二的地址。所以上述sizeof(X)结果为1
(2)、虚继承类的大小
在虚继承的子类中,子类除了vptr,还会增加一种形式的指针。这个指针或者指向虚基类子对象,或者指向一个相关的表格,表格中存放的不是虚基类子对象的地址,就是其偏移量,这个指针被称为bptr。(在同时存在vptr和bptr的时候,某些编译器会将其优化,合并为一个指针)
故上述Y和Z,自身包含指针bptr(占四个字节),继承X的非静态成员变量(占0个字节),故sizeof(Y)和sizeof(Z)结果都为4。
(3)、类A的大小
A是直接从Y和Z多继承而来,由于X是一个虚基类(子类都虚继承),所以在A中仅仅会存在一个X类的副本。整个A的对象结构为:
类Y的bptr(4字节)
类Y的非静态成员(0字节)
类Z的bptr(4字节)
类Z的非静态成员(0字节)
类A的非静态成员(0字节)
类X的非静态成员(0字节)
故sizeof(X)结果为8。这里从上往下分别是Y和Z的顺序,是由类A的继承顺序决定的。
参考:https://www.cnblogs.com/fanzhidongyzby/archive/2013/01/14/2859064.html
posted on 2018-05-04 10:53 chenjx_ucs 阅读(498) 评论(0) 编辑 收藏 举报