c++中虚函数表的理解

虚函数表是一个类的虚函数的地址表,解决了继承和覆盖的问题,其内容反映类中真实的函数。在一个含有虚函数的类的实例中,这个表存在实例的内存中,编译器在编译的时候都会讲这个表置于实例内存的最前面。一般来说,实例的地址就是虚函数表的地址。也就是说可以通过实例的地址获取到这个表的首地址。

定义如下的基类:

class base{
public:
	base(int x) :a(x){
		cout << "base::base(x) x = " << x << endl;
	}
	~base(void){
		cout << "base::~base(void)" << endl;
	}
	virtual void vf1(void){
		cout << "base::vf1" << endl;
	}
	virtual void vf2(void){
		cout << "base::vf2" << endl;
	}
	virtual void vf3(void){
		cout << "base::vf3" << endl;
	}
private:
	int a;
};

这样在主函数中可以通过如下的方式访问虚函数:

typedef void(*pFUN)(void);
base b(3);
pFUN pfun;
pfun = (pFUN)*((int*)*(int*)&b + 0);
pfun();
pfun = (pFUN)*((int*)*(int*)&b + 1);
pfun();
pfun = (pFUN)*((int*)*(int*)&b + 2);
pfun();

在继承的情况下,分为单继承和多继承。单继承的情况下,一个子类的实例会仅有一张基类的虚函数表,如果子类有对基类的虚函数覆写,那么虚函数表中相对应的那个虚函数也随之改变,子类中新定义的基类会随之添加在这个虚函数表的后面。

多继承的情况下,会有多张虚函数表,一个基类一张虚函数表。和单继承的情况一样,如果子类中有对基类的虚函数覆写,那么相对应的虚函数表也会随之改变,新增加的虚函数,添加到虚函数表后面。

完整代码如下:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

// test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#pragma warning(disable:4996)
#include <string>

using namespace std;

class base{
public:
	base(int x) :a(x){
		cout << "base::base(x) x = " << x << endl;
	}
	~base(void){
		cout << "base::~base(void)" << endl;
	}
	virtual void vf1(void){
		cout << "base::vf1" << endl;
	}
	virtual void vf2(void){
		cout << "base::vf2" << endl;
	}
	virtual void vf3(void){
		cout << "base::vf3" << endl;
	}
private:
	int a;
};

class base0{
public:
	base0(int x) :a(x){
		cout << "base0::base0(x) x = " << x << endl;
	}
	~base0(void){
		cout << "base0::~base0(void)" << endl;
	}
	virtual void vf1(void){
		cout << "base0::vf1" << endl;
	}
	virtual void vf2(void){
		cout << "base0::vf2" << endl;
	}
	virtual void vf3(void){
		cout << "base0::vf3" << endl;
	}
private:
	int a;
};

/*继承了基类,但是并没有覆写基类的虚函数*/
class child1 :public base{
private:
	int b;
public:
	child1(int x,int y) :b(x),base(y){
		cout << "child1::child1(int x) b=" << b << endl;
	}
	~child1(void){
		cout << "child1::~child1" << b << endl;
	}
	virtual void vfch1(void){
		cout << "child1::cfch1" << endl;
	}
	virtual void vfch2(void){
		cout << "child1::cfch2" << endl;
	}
};

/*继承基类并覆写基类的虚函数*/
class child2 :public base{
private:
	int b;
public:
	child2(int x, int y) :b(x), base(y){
		cout << "child2::child2(int x) b=" << b << endl;
	}
	~child2(void){
		cout << "child2::~child2" << b << endl;
	}
	virtual void vf1(void){
		cout << "overwrite base vf1 child2::vf1" << endl;
	}
	virtual void vfch2(void){
		cout << "child2::cfch2" << endl;
	}
};
/*多重继承无覆写*/
class child3 :public base, public base0{
private:
	int b;
public:
	child3(int x, int y, int z) :b(x), base(y), base0(z){
		cout << "child3:child3() b=" << b << endl;
	}
	~child3(void)
	{
		cout << "child3:~child3()" << endl;
	}
	virtual void vfch3(void){
		cout << "child3:;vfch3" << endl;
	}

};
/*多重继承有覆写*/
class child4 :public base, public base0{
private:
	int b;
public:
	child4(int x, int y, int z) :b(x), base(y), base0(z){
		cout << "child4:child4() b=" << b << endl;
	}
	~child4(void)
	{
		cout << "child4:~child4()" << endl;
	}
	virtual void vfch4(void){
		cout << "child4::vfch4()" << endl;
	}
	virtual void vf1(void){
		cout << "child4::vf1()" << endl;
	}
};
typedef void(*pFUN)(void);
int main(int argc, char *argv[])
{
	base *pb = NULL;
	base0 *pb0 = NULL;
	base b(3);
	cout << "使用函数指针的形式直接访问基类base的虚函数:" << endl;
	pFUN pfun;
	pfun = (pFUN)*((int*)*(int*)&b + 0);
	pfun();
	pfun = (pFUN)*((int*)*(int*)&b + 1);
	pfun();
	pfun = (pFUN)*((int*)*(int*)&b + 2);
	pfun();
	cout << "普通单继承无覆写child1" << endl;
	pb = new child1(2,3);
	pb->vf1();
	pb->vf2();
	pb->vf3();
	delete pb;
	pb = NULL;
	cout << "普通单继承有覆写child2" << endl;
	pb = new child2(5,6);
	pb->vf1();
	pb->vf2();
	pb->vf3();
	delete pb;
	pb = NULL;
	cout << "多重继承无覆写child3" << endl;
	child3 ch3(7, 8, 9);
	pb = &ch3;
	pb0 = &ch3;
	cout << "pb output:" << endl;
	pb->vf1();
	pb->vf2();
	pb->vf3();
	cout << "pb0 output:" << endl;
	pb0->vf1();
	pb0->vf2();
	pb0->vf3();
	cout << "多重继承有覆写child4" << endl;
	child4 ch4(11, 34, 56);
	pb = &ch4;
	pb0 = &ch4;
	cout << "pb output:" << endl;
	pb->vf1();
	pb->vf2();
	pb->vf3();
	cout << "pb0 output:" << endl;
	pb0->vf1();
	pb0->vf2();
	pb0->vf3();
	cout << "***********************" << endl;
	return 0;

}

输出结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值