#include <iostream>
using namespace std;
class Base1 {
public:
virtual void fun()
{
cout << "Base1::fun" << endl;
}
virtual void foo()
{
cout << "Base1::foo" << endl;
}
Base1()
{
printf("Base1\n");
}
~Base1()
{
printf("~Base1\n");
}
};
class Base2 {
public:
virtual void fun()
{
cout << "Base2::fun" << endl;
}
virtual void foo()
{
cout << "Base2::foo" << endl;
}
Base2()
{
printf("Base2\n");
}
~Base2()
{
printf("~Base2\n");
}
};
class Derive : public Base1, public Base2{
public:
virtual void fun()
{
cout << "Derive::fun" << endl;
}
virtual void foo1()
{
cout << "Derive::foo1" << endl;
}
Derive()
{
printf("Derive\n");
}
~Derive()
{
printf("~Derive\n");
}
};
int main()
{
Derive d;
Base1 *b1 = &d;
b1->fun();
b1->foo();
Base2 *b2 = &d;
b2->fun();
b2->foo();
return 0;
}
根据继承关系的顺序,首先调用了基类Base1的构造函数。在调用另一个基类Base2时, 并不是直接将对象的首地址作为this指针传递,而是向后调整了基类Base1的大小,以调整后的地址值作为this指针,最后再调用基类Base2的构造函数。
由于有了两个基类,因此子类在继承时也将他们的虚表指针一起继承了过来,也就有了两个虚表指针。在多继承中,派生类虚表指针的个数取决于所继承的基类个数。
在转换Base2指针时,je short 001A65E5会调整首地址并跳过第一个基类所占用的空间。
由于具有多个同级的基类,因此早派生类中产生了多个虚表指针。在对基类进行析构时,需要设置this指针,用于调用基类的析构函数。由于具有多个基类,当在析构的过程中调用各个基类的析构函数时,传递的首地址将有所不同,编译器会根据每个基类在对象中占用的空间位置,对应地传入各个基类部分首地址作为this指针。
总结:
单继承:
- 在类对象占用的内存空间中,只保存一份虚表指针。
- 由于只有一个虚表指针,对应的也只有一个虚表。
- 虚表中各项保存了类中各虚函数的首地址。
- 构造时先构造基类,在构造自身,并且只调用一次基类构造函数。
- 析构时先析构自身,在析构基类,并且只调用一次基类析构函数。
多重继承类:
- 在类对象中所占的内存空间中,根据继承基类的个数保存对应的虚表指针。
- 根据所保存的虚表指针的个数,对应产生相应个数的虚表。
- 构造时需要调用多个基类构造函数。
- 转换基类指针时,需要调转到对应的首地址。
- 构造时先构造继承列表中第一个基类,然后依次调用到最后一个继承的基类构造函数
- 析构时先析构自身,然后以与构造函数相反的顺序调用所有基类的析构函数。