浅谈多态中的虚函数和虚表

需要实现多态必不可少的就是虚函数,类的成员函数前加virtual关键字,这个成员函数就是虚函数;例如:

class T
{
	public:
	
	virtual void fun()
	{
		cout<<"fun()"<<endl;
	}
	
	int _t;

};
在不加virtual的情况下:sizeof(T)的大小为4;
加了vitual变成虚函数之后:sizeof(T)的大小为8;
这是为什么呢??
   
存在虚函数的类的对象模型为:

由此图可以看出T的对象中不仅有_t而且还有一个指针,这个指针指向的是一个存放虚函数地址的表,也就是虚表。所以在类成员函数前加了virtual之后的大小为8;
根据下图就可以看出虚表中是怎么去存放虚函数的地址:

在单继承下的虚函数表又是什么样??

class T{
public:
	  virtual void fun1()
	{
		cout << "T::fun1()" << endl;
	}

	 virtual  void fun2()
	  {
		  cout << "T::fun1()" << endl;
	  }
	int _t;
};

class Z : public T{
public:
	virtual void fun1()
	{
		cout << "Z::fun1" << endl;
	}

	virtual void fun3()
	{
		cout << "Z::fun3" << endl;
	}
	int _z;
};
上述代码中,类Z单继承T,重写了T类中的fun1,fun2并没有重写,在Z类本身中还加了自己的虚函数fun3;
Z的对象模型为:

vs2013监视窗口:

由上图监视窗口可以看出在__vfPtr所指的虚表中只有Z::fun1和T::fun2这两个虚函数的地址,fun3并没有存在于虚表中,这是因为vs2013下编译器的一个bug,不过我们
换一种方式(打印虚表)来看虚表:

class T{
public:
	  virtual void fun1()
	{
		cout << "T::fun1()" << endl;
	}

	 virtual  void fun2()
	  {
		  cout << "T::fun1()" << endl;
	  }
	int _t;
};

class Z : public T{
public:
	virtual void fun1()
	{
		cout << "Z::fun1()" << endl;
	}

	virtual void fun3()
	{
		cout << "Z::fun3()" << endl;
	}
	int _z;
};

typedef void (*V_F) ();

void PrintVtable(int vptr)
{
	int * ptr = (int *)vptr;

	printf("虚表:0x%p\n",ptr);

	for (int i = 0; ptr[i] != 0; i++) //通常虚表以0为结束标志;
	{
		V_F f = (V_F)ptr[i];
		f();
	}
}

void test()
{
	Z z;
	PrintVtable(*(int*)(&z));
}

运行截图:

多继承的虚函数表:

class T{
public:
	  virtual void fun1()
	{
		cout << "T::fun1()" << endl;
	}

	 virtual  void fun2()
	  {
		  cout << "T::fun2()" << endl;
	  }
	int _t;
};

class Z {
public:
	virtual void fun1()
	{
		cout << "Z::fun1()" << endl;
	}

	virtual void fun2()
	{
		cout << "Z::fun2()" << endl;
	}
	int _z;
};

class P : public Z,public T{
public:
	virtual void fun1()
	{
		cout << "P::fun1()" << endl;
	}

	virtual void fun3()
	{
		cout << "P::fun3()" << endl;
	}
};

typedef void (*V_F) ();

void PrintVtable(int vptr)
{
	int * ptr = (int *)vptr;

	printf("虚表:0x%p\n",ptr);

	for (int i = 0; ptr[i] != 0; i++) //通常虚表以0为结束标志;
	{
		V_F f = (V_F)ptr[i];
		f();
	}
}

void test()
{
	
	P p;
	PrintVtable(*(int *)(&p));
}
运行截图:

可以看出在虚函数表中没有出现虚函数T::fun2();这是因为派生类中的虚函数会放在第一个继承的虚表中;


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值