C++多重继承虚函数表结构


在网上看到陈皓写的一篇关于虚函数表的解析的博客,讲的很好,但是关于多重继承那一块不是很理解。

先看下列代码:

   
  #include <iostream>
  

using namespace std;

class Base1 {
public:
//虚函数定义
virtual void f() { cout << "Base1::f" << endl; }
virtual void g() { cout << "Base1::g" << endl; }
virtual void h() { cout << "Base1::h" << endl; }

};

class Base2 {
public:
//虚函数定义
virtual void f() { cout << "Base2::f" << endl; }
virtual void g() { cout << "Base2::g" << endl; }
virtual void h() { cout << "Base2::h" << endl; }

};

class Base3 {
public:
//虚函数定义
virtual void f() { cout << "Base3::f" << endl; }
virtual void g() { cout << "Base3::g" << endl; }
virtual void h() { cout << "Base3::h" << endl; }

};

//多继承时的情况---无虚函数覆盖
class DerivedMulti:public Base1,public Base2,public Base3{
public:
//虚函数定义
virtual void f1() { cout << "DerivedMulti::f1" << endl; }
virtual void g1() { cout << "DerivedMulti::g1" << endl; }
};

int main()
{
typedef void(*Fun)(void);
cout << "多重继承时的情况(无虚函数覆盖):" << endl;
DerivedMulti dMultiObj;
cout << "DerivedMulti类第一个虚函数表地址:" << (int*)(&dMultiObj) << endl;
cout << "依次调用三个虚函数表中的虚函数:" << endl;
cout << "第一个虚函数表中的虚函数:" << endl;
Fun pFun = NULL;
pFun = (Fun)*((int *)*((int*)(&dMultiObj)));
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 1);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 2);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 3);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 4);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 5);
pFun();
cout << "第二个虚函数表中的虚函数:" << endl;
pFun = (Fun)*((int *)*((int*)(&dMultiObj + 1)));
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj + 1)) + 1);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj + 1)) + 2);
pFun();
cout << "第三个虚函数表中的虚函数:" << endl;
pFun = (Fun)*((int *)*((int*)(&dMultiObj + 2)));
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj + 2)) + 1);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj + 2)) + 2);
pFun();

return 0;
}

请输入图片描述
上述代码是关于多重继承无虚函数覆盖时的情况,按照博客上所说的,子类虚函数表的结构应该如下所示:

请输入图片描述

但是我在代码中依次访问各个虚函数表中出现的虚函数时,运行到第二个虚函数表时程序就异常终止了:

请输入图片描述

谁能帮忙看看是什么原因?

运行环境是:Codeblocks 10.05(GCC)

面向对象 C++

依尔sama 11 years, 7 months ago

修改了你的代码,下面这样才是正确的

   
  int main()
  
{
typedef void(*Fun)(void);
cout << "多重继承时的情况(无虚函数覆盖):" << endl;
DerivedMulti dMultiObj;
cout << "DerivedMulti类第一个虚函数表地址:" << (int*)(&dMultiObj) << endl;
cout << "依次调用三个虚函数表中的虚函数:" << endl;
cout << "第一个虚函数表中的虚函数:" << endl;
Fun pFun = NULL;
pFun = (Fun)*((int *)*((int*)(&dMultiObj)));
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 1);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 2);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 3);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)) + 4);
pFun();
cout << "第二个虚函数表中的虚函数:" << endl;
pFun = (Fun)*((int *)*((int*)(&dMultiObj)+ 1));
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)+ 1) + 1);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj)+ 1) + 2);
pFun();
cout << "第三个虚函数表中的虚函数:" << endl;
pFun = (Fun)*((int *)*((int*)(&dMultiObj )+ 2));
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj )+ 2) + 1);
pFun();
pFun = (Fun)*((int *)*((int*)(&dMultiObj )+ 2) + 2);
pFun();

return 0;
}

pFun = (Fun) ((int *) ((int )(&dMultiObj)) + 5); //这里已经越界了,错误。 pFun = (Fun) ((int ) ((int )(&dMultiObj + 1))); //这里错误,指针越界了。 (&dMultiObj + 1) 这里的指针运算是DerivedMulti 的指针运算,地址是0x22ff1c;指向下一个DerivedMulti了。
改为((int*)(&dMultiObj)+ 1) 这样才是指向下一个虚函数指针vptr。
看一下DerivedMulti 的内存布局图就清楚了。

请输入图片描述

Alamith answered 11 years, 7 months ago

Your Answer