天天看點

淺談多态中的虛函數和虛表

需要實作多态必不可少的就是虛函數,類的成員函數前加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();這是因為派生類中的虛函數會放在第一個繼承的虛表中;

繼續閱讀