一、可以先看看这个链接
二、从内存布局看虚继承原理
1、普通类的菱形继承:虚基类的成员会被拷贝两份,一模一样的,导致了空间的浪费;
class A {
public:
int age=10;
};
class B: public A {
public:
int b;
};
class C : public A {
public:
int c;
};
class D : public B, public C {
public:
int d;
};
2、基于虚基类的菱形继承
class A {
public:
int age=10;
};
class B:virtual public A {
public:
int b;
};
class C :virtual public A {
public:
int c;
};
class D : public B, public C {
public:
int d;
};
类A的结构:和其正常的类一样,只拥有自己的成员变量
类B的结构:由于对A的虚继承,所以除了B本身的成员外,还有一个指针变量(虚基类指针),指向一个整数,该整数是类B中继承A的成员变量的位置偏移量,最后还继承了A的成员变量(指针,B的成员变量b,A的成员变量age)
类C的结构:由于对A的虚继承,所以除了C本身的成员外,还有一个指针变量(虚基类指针),指向一个整数,该整数是类C中继承A的成员变量的位置偏移量,最后还继承了A的成员变量(指针,C的成员变量c,A的成员变量age)
类D的结构:B 和C都是D的父类,所以会继承B、C中的指针(虚基类指针)和成员变量b、c,同时因为BC都是虚继承于A,所以D中的来自A的成本变量age只有一份,再加上自身的d,一共是6*4=24字节;
**
- 如何查看类的结构(限于windows平台的VS:)
**
cl /d1 reportSingleClassLayout类名 \cpp路径\test.cpp
- 虚继承之所以产生虚基类指针和虚基类表,都是为了保证不管多少层的继承,虚基类的数据只有一份,从而避免二义性和不浪费类对象内存空间;(虚基类表不占用类对象的空间);
- vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual
table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。
三、虚继承和虚函数
1、相似之处:都使用了虚指针(均占用类对象存储空间)和虚表(均不占用类对象的存储空间)
2、虚基类依旧存在继承类中,只占用存储空间;虚函数不占用存储空间。
3、虚基类表存储的是虚基类相对***直接继承类***的偏移;而虚函数表存储的是虚函数地址。
**
- 暂时记录到这里,以后有新体会再加上!
**