深入探索c++虚函数继承模型

来源:互联网 发布:mac page up 编辑:程序博客网 时间:2024/06/01 09:53

关于c++虚函数的继承模型,在http://blog.csdn.net/haoel/article/details/1948051/一文中有详细的介绍,本文只是对虚函数继承的验证,具体如下。

示例代码:

<pre name="code" class="cpp">#include<stdlib.h>#include<iostream>#include<fstream>#include<stdio.h>#include<time.h>#include<memory.h>#include<math.h>#include<windows.h>#include<math.h>#include<conio.h>#include<iomanip>#include<string>#include<vector>using namespace std;class Base {public:int a;virtual void f() { cout << "Base::f" << endl; }virtual void g() { cout << "Base::g" << endl; }virtual void h() { cout << "Base::h" << endl; }};class Derived : public Base{public:int b;virtual void f() { cout << "Derived::f" << endl; }virtual void g1() { cout << "Derived::g1" << endl; }virtual void h1() { cout << "Derived::h1" << endl; }};int main(){typedef void(*Fun)(void);//Fun是一个函数指针的类型声明,形参表为空,返回值也为空Base b;b.a = 11;Fun pFun = NULL;cout << "对象的地址是:" << &b << endl;//整个对象b的地址cout << "对象b中a的值是:" << *((int *)(&b)+1) << endl;//对象b中数据成员a的值cout << "虚函数表地址:" << (int *)*(int*)(&b) << endl;//虚函数表的地址//先得到vptr即虚表数组首地址,然后解引用得到vtbl数组中的第一个函数地址cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;cout << "虚函数表 — 第二个函数地址:" << (int*)*(int*)(&b) + 1 << endl;cout << "虚函数表 — 第三个函数地址:" << (int*)*(int*)(&b) + 2 << endl;pFun = (Fun)*((int*)*(int*)(&b));//将第一个函数地址赋值给pfunpFun();pFun = (Fun)*((int*)*(int*)(&b) + 0); // Base::f()pFun();pFun = (Fun)*((int*)*(int*)(&b) + 1); // Base::g()pFun();pFun = (Fun)*((int*)*(int*)(&b) + 2); // Base::h()pFun();Derived c;c.a = 22;cout << "对象的地址是:" << &c << endl;cout << "虚函数表地址:" << (int*)(&c) << endl;//先得到vptr即虚表数组首地址,然后解引用得到vtbl数组中的第一个函数地址cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&c) << endl;cout << "虚函数表 — 第二个函数地址:" << (int*)*(int*)(&c) + 1 << endl;cout << "虚函数表 — 第三个函数地址:" << (int*)*(int*)(&c) + 2 << endl;cout << "虚函数表 — 第四个函数地址:" << (int*)*(int*)(&c) + 3 << endl;cout << "虚函数表 — 第五个函数地址:" << (int*)*(int*)(&c) + 4 << endl;pFun = (Fun)*((int*)*(int*)(&c));//将第一个函数地址赋值给pfunpFun();pFun = (Fun)*((int*)*(int*)(&c) + 0); // Base::f()pFun();pFun = (Fun)*((int*)*(int*)(&c) + 1); // Base::g()pFun();pFun = (Fun)*((int*)*(int*)(&c) + 2); // Base::h()pFun();pFun = (Fun)*((int*)*(int*)(&c) + 3); // Base::h()pFun();pFun = (Fun)*((int*)*(int*)(&c) + 4); // Base::h()pFun();cout << sizeof(b) << endl;//一个基类对象所占空间的大小cout << sizeof(c) << endl;//一个派生类对象所占大小cout << sizeof(Derived) << endl;return 0;}
运行结果:


当我们在

pFun = (Fun)*((int*)*(int*)(&c) + 4); // Base::h()pFun();
后面加上

pFun = (Fun)*((int*)*(int*)(&c) + 5); // Base::h()pFun();
之后,运行结果如下:



通过结果对比我们可以确定

1.在基类中对象b所占空间大小为8个字节(虚函数表指针+int型变量a),派生对象c所占空间大小为12字节(虚函数表指针4个字节+两个int整形的值);

2.基类的虚函数表一共占12个字节(包含三个函数的入口地址,每个函数的入口地址占4个字节),派生类虚函数表大小为20字节(重写了基类的f()函数的入口地址+基类中g()和h()的入口地址+派生类对象自身的g1()和h1()函数入口地址)

3.当偏量加到5时,出现访问冲突,说明派生类的虚函数表只有5个函数的入口地址;


0 0
原创粉丝点击