虚函数表是一个类的虚函数的地址表,解决了继承和覆盖的问题,其内容反映类中真实的函数。在一个含有虚函数的类的实例中,这个表存在实例的内存中,编译器在编译的时候都会讲这个表置于实例内存的最前面。一般来说,实例的地址就是虚函数表的地址。也就是说可以通过实例的地址获取到这个表的首地址。
定义如下的基类:
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;
}
输出结果: