多重继承虚函数表分析
演示在多重继承下,虚函数表的样子
创建两个父类Base1 Base2 ,并创建Derived 先后继承Base1 Base2 ,查看对于各个函数的调用结果
#include <iostream>
using namespace std;
class Base1
{
public:
virtual void f() {
cout << "Base1::f()" << endl;
}
virtual void g() {
cout << "Base1::g()" << endl;
}
};
class Base2
{
public:
virtual void h() {
cout << "Base2::h()" << endl;
}
virtual void i() {
cout << "Base2::i()" << endl;
}
};
class Derived : public Base1, public Base2
{
public:
virtual void f() {
cout << "Derived::f()" << endl; // 只覆盖Base1的f
}
virtual void i() {
cout << "Derived::i()" << endl; // 只覆盖Base2的i
}
// 如下三个是本类自己的虚函数
virtual void mh() {
cout << "Derived::mh()" << endl;
}
virtual void mi() {
cout << "Derived::mi()" << endl;
}
virtual void mj() {
cout << "Derived::mj()" << endl;
}
};
int main()
{
typedef void(*Func)(void); // 定义了一个函数指针,typedef就代表Func是一个函数指针类型,可以将它当作类型使用
cout << "sizeof(Base1)" << " = " << sizeof(Base1) << endl;
cout << "sizeof(Base2)" << " = " << sizeof(Base2) << endl;
cout << "sizeof(Derived)" << " = " << sizeof(Derived) << endl;
cout << "子类的大小有8且无成员变量,说明有两个虚函数指针" << endl;
Derived ins; // 子类对象
Base1& b1 = ins; // 父类指针指向子类
Base2& b2 = ins; // 父类指针指向子类
Derived& d = ins; // 子类指针指向子类
// 第一个虚函数指针(子类的)
long* pderived1 = (long*)(&ins);
long* vptr1 = (long*)(*pderived1);
// 第二个虚函数指针(子类的)
long* pderived2 = pderived1 + 1;
long* vptr2 = (long*)(*pderived2);
// 先从第一个继承的父类里找函数,如果覆盖的,就弄成自己的,如果自己没覆盖,就弄成父亲的
// 子类分别覆盖了 f, i
Func f1 = (Func)vptr1[0]; // Derived::f()
Func f2 = (Func)vptr1[1]; // Base1::g()
Func f3 = (Func)vptr1[2]; // Derived::mh()
Func f4 = (Func)vptr1[3]; // Derived::mi()
Func f5 = (Func)vptr1[4]; // Derived::mj()
Func f6 = (Func)vptr1[5];
Func f7 = (Func)vptr1[6];
Func f8 = (Func)vptr1[7];
// 这里找另一个父类
Func f11 = (Func)vptr2[0]; // Base2::h
Func f22 = (Func)vptr2[1]; // Derived::i()
Func f33 = (Func)vptr2[2];
Func f44 = (Func)vptr2[3];
Func f55 = (Func)vptr2[4];
cout << "-------------------" << endl;
cout << "父类指针指向子类,调用函数得到的都是子类的虚函数" << endl;
b1.f(); // Derived::f()
b2.i(); // Derived::i()
d.f(); // Derived::f()
d.i(); // Derived::i()
d.mh(); // Derived::mh()
cout << "-------------------" << endl;
cout << "打印子类第一个虚函数表,对应Base1,子类覆盖了Base::f()" << endl;
f1();
f2();
f3();
f4();
f5();
//f6(); 无法访问
cout << "-------------------" << endl;
cout << "打印子类第二个虚函数表,对应Base2,子类覆盖了Base::i()" << endl;
cout << "并且第二个虚函数表里面无法访问子类自己的虚函数,说明子类的虚函数都在第一个虚函数表" << endl;
f11();
f22();
//f33(); 无法访问
//f44(); 无法访问
//f55(); 无法访问
cout << "-------------------" << endl;
return 0;
}
sizeof(Base1) = 4
sizeof(Base2) = 4
sizeof(Derived) = 8
子类的大小有8且无成员变量,说明有两个虚函数指针
-------------------
父类指针指向子类,调用函数得到的都是子类的虚函数
Derived::f()
Derived::i()
Derived::f()
Derived::i()
Derived::mh()
-------------------
打印子类第一个虚函数表,对应Base1,子类覆盖了Base::f()
Derived::f()
Base1::g()
Derived::mh()
Derived::mi()
Derived::mj()
-------------------
打印子类第二个虚函数表,对应Base2,子类覆盖了Base::i()
并且第二个虚函数表里面无法访问子类自己的虚函数,说明子类的虚函数都在第一个虚函数表
Base2::h()
Derived::i()
-------------------
虚函数表图片
- 子类对象
ins 有两个虚函数表指针,vptr1 vptr2 - 类
Derived 有两个虚函数表,因为它继承自两个基类 - 子类和第一个基类共用一个
vptr ,也可以说共用一个虚函数表 - 子类中的虚函数覆盖了父类中的同名虚函数
|