1.虚基类
什么是虚基类,虚基类的作用是什么?
首先虚基类是为了解决多继承产生的二义性问题,范例代码如下:
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <Windows.h>
using namespace std;
class Base {
public:
int m_base_a;
};
class A :public Base {
public:
int m_A_a;
};
class B :public Base {
public:
int m_B_a;
};
class Derived :public A, public B {
public:
int m_D_a;
};
int main() {
Derived *b = new Derived();
b->m_base_a = 10;
return 0;
}
此时编译代码会报错,因为子类Derived对象有两份爷爷类Base的对象内存,一份是A类继承而来,一份是B类继承而来。在这里编译器无法判断当前需要赋值的m_base_a是来自A还是B。如果改成b->A::m_base_a = 10;则编译器不会报错,但是对于子类Derived另一份Base对象是多余的,造成了内存的浪费。因此C++引入了虚基类来解决这个问题,当子类继承多个类,且多个父类都继承一个爷爷类时,子类对象就保留一份爷爷对象空间。父类在继承爷爷类需要加上virtual关键字,具体代码如下:
class Base {
public:
int m_base_a;
};
class A :virtual public Base {
public:
int m_A_a;
};
class B :virtual public Base {
public:
int m_B_a;
};
class Derived :public A, public B {
public:
int m_D_a;
};
int main() {
Derived *b = new Derived();
b->m_base_a = 10;
return 0;
}
其中Base 就是虚基类
2.虚基类表和虚基类表指针
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <Windows.h>
using namespace std;
class Base {
public:
int m_base_a;
};
class A :virtual public Base {
public:
int m_A_a;
};
class B :virtual public Base {
public:
int m_B_a;
};
class Derived :public A, public B {
public:
int m_D_a;
};
int main() {
Derived *b = new Derived();
cout << "Base sizeof " << sizeof(Base) << " A sizeof " << sizeof(A) << " B sizeof " << sizeof(B) << "Derived sizeof " << sizeof(Derived)<<endl;
b->m_base_a = 10;
return 0;
}
打印这三个类对象的内存占用大小:
class Base大小为4字节好理解,就是m_base_a占用的大小。
class A的大小12字节,其中继承Base成员m_base_a占四字节,自己成员m_A_a占用,还有四字节就是虚基类表指针
class B与A一样
最后子类Derived对象大小为24字节,其中m_base_a,m_A_a,m_B_a,m_D_a占16字节,还有8字节时继承A和B类的虚基类表指针
说明:虚基类表一般是8字节,每多一个虚基类就多4字节,虚基类表其实就是存储虚基类对象在子类对象的偏移量,让子类对象能够访问到虚基类对象。