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

关于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));//将第一个函数地址赋值给pfun
	pFun();
	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));//将第一个函数地址赋值给pfun
	pFun();
	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个函数的入口地址;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值