假设是32位机器。
在这里,解释一下虚函数表(Virtual table 或称为vtbl),虚函数指针( Virtual pointer 或者称为 vptr)的内部工作原理。
首先,我们必须了解一下内存布局。
例一:类的内存布局
#include <iostream>
using namespace std;
class Test{
public:
int data1;
int data2;
int fun1();
};
int main(){
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
cout << "obj 's Address = " << &obj << endl;
return 0;
}
输出结果:
Sobj's Size = 8
obj 's Address = 0012FF7C
注意:任何的成员函数都不会占用任何的内存。
例二 :派生类的内存布局
// 父类
class Test{
public:
int a;
int b;
};
// 派生类
class dTest : public Test{
public:
int c;
};
int main(){
Test obj1;
cout << "obj1's Size = " << sizeof(obj1) << endl;
cout << "obj1's Address = " << &obj1 << endl;
dTest obj2;
cout << "obj2's Size = "<< sizeof(obj2) << endl;
cout << "obj2's Address = "<< &obj2 << endl;
return 0;
}
输出结果:
obj1's Size = 8
obj1's Address = 0012FF78
obj2's Size = 12
obj2's Address = 0012FF6C
例三 : 带有虚函数类的内存布局
// 带有虚函数的类
class Test{
public:
int data;
// 虚函数
virtual void fun1(){
cout << "Test::fun1" << endl;
}
};
int main(){
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
cout << "obj's Address = " << &obj << endl;
return 0;
}
输出结果:
obj's Size = 8
obj's Address = 0012FF7C
注意:在类中添加虚函数会产生额外的负担(4Byte)
例四:不止一个虚函数
class Test{
public:
int data;
virtual void fun1() { cout << "Test::fun1" << endl; }
virtual void fun2() { cout << "Test::fun2" << endl; }
virtual void fun3() { cout << "Test::fun3" << endl; }
virtual void fun4() { cout << "Test::fun4" << endl; }
};
int main(){
Test obj;
cout << "obj's Size = " << sizeof(obj) << endl;
cout << "obj's Address = " << &obj << endl;
return 0;
}
输出结果:
obj's Size = 8
obj's Address = 0012FF7C
注意:如果一个类中有虚函数的前提下,再增加虚函数就不会产生额外的内存负担。仍然产生额外的4Byte负担。
例五:
class Test{
public:
int a;
int b;
Test(int temp1 = 0, int temp2 = 0){
a=temp1;
b=temp2;
}
int getA(){
return a;
}
int getB(){
return b;
}
virtual ~Test();
};
int main(){
Test obj(5, 10);
// Changing a and b
int* pInt = (int*)&obj;
*(pInt+0) = 100;
*(pInt+1) = 200;
cout << "a = " << obj.getA() << endl;
cout << "b = " << obj.getB() << endl;
return 0;
}
输出结果:
a = 200
b = 10
如果作如下修改:
// Changing a and b
int* pInt = (int*)&obj;
*(pInt+1) = 100; // In place of 0
*(pInt+2) = 200; // In place of 1
输出结果:
a = 100
b = 200
注意:位于class第一位置是vptr,其他都位于其后面。
(Who sits 1st place of Class : Answer is VPTR,VPTR - 1st placed in class and rest sits after it. )
例六:
class Test {
virtual void fun1(){
cout << "Test::fun1" << endl;
}
};
int main(){
Test obj;
cout << "VPTR's Address " << (int*)(&obj+0) << endl;
cout << "VPTR's Value " << (int*)*(int*)(&obj+0) << endl;
return 0;
}
输出结果:
VPTR's Address 0012FF7C
VPTR's Value 0046C060
注意:VPTR’s Value是Virtual table的地址,让我们下面的例子。
例七:
class Test{
virtual void fun1(){
cout << "Test::fun1" << endl;
}
};
typedef void (*Fun)(void);
int main(){
Test obj;
cout << "VPTR's Address " << (int*)(&obj+0) << endl;
cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << endl; // Value of VPTR
cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl;
Fun pFun = (Fun)*(int*)*(int*)(&obj+0); // calling Virtual function
pFun();
return 0;
}
输出结果:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1
例八:
class Test{
virtual void fun1() { cout << "Test::fun1" << endl; }
virtual void func1() { cout << "Test::func1" << endl; }
};
int main(){
Test obj;
cout << "VPTR's Address " << (int*)(&obj+0) << endl;
cout << "VIRTUAL TABLE 's Address"<< (int*)*(int*)(&obj+0) << endl;
// Calling Virtual table functions
cout << "Value at 1st entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+0) << endl;
cout << "Value at 2nd entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+1) << endl;
return 0;
}
输出结果:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Value at 2nd entry of VIRTUAL TABLE 004012
例九:
class Test{
virtual void fun1() { cout << "Test::fun1" << endl; }
virtual void func1() { cout << "Test::func1" << endl; }
};
typedef void(*Fun)(void);
int main(){
Test obj;
Fun pFun = NULL;
// calling 1st virtual function
pFun = (Fun)*((int*)*(int*)(&obj+0)+0);
pFun();
// calling 2nd virtual function
pFun = (Fun)*((int*)*(int*)(&obj+0)+1);
pFun();
return 0;
}
输出结果:
Test::fun1
Test::func1
例十:
class Base1{
public:
virtual void fun();
};
class Base2{
public:
virtual void fun();
};
class Base3{
public:
virtual void fun();
};
class Derive : public Base1, public Base2, public Base3{
};
int main(){
Derive obj;
cout << "Derive's Size = " << sizeof(obj) << endl;
return 0;
}
输出结果:
Derive's Size = 12
例十一:
class Base1{
virtual void fun1() { cout << "Base1::fun1()" << endl; }
virtual void func1() { cout << "Base1::func1()" << endl; }
};
class Base2 {
virtual void fun1() { cout << "Base2::fun1()" << endl; }
virtual void func1() { cout << "Base2::func1()" << endl; }
};
class Base3 {
virtual void fun1() { cout << "Base3::fun1()" << endl; }
virtual void func1() { cout << "Base3::func1()" << endl; }
};
class Derive : public Base1, public Base2, public Base3{
public:
virtual void Fn(){
cout << "Derive::Fn" << endl;
}
virtual void Fnc(){
cout << "Derive::Fnc" << endl;
}
};
typedef void(*Fun)(void);
int main(){
Derive obj;
Fun pFun = NULL;
// calling 1st virtual function of Base1
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
pFun();
// calling 2nd virtual function of Base1
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
pFun();
// calling 1st virtual function of Base2
pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);
pFun();
// calling 2nd virtual function of Base2
pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);
pFun();
// calling 1st virtual function of Base3
pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);
pFun();
// calling 2nd virtual function of Base3
pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);
pFun();
// calling 1st virtual function of Drive
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
pFun();
// calling 2nd virtual function of Drive
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
pFun();
return 0;
}
输出结果:
Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Drive::Fn
Drive::Fnc
顺便提一下函数指针:
int i;
定义了一个int类型的变量i;
而这样
typedef INT int;
表示用户自己定义了一个整型数据类型INT,实际上就等同于int
所以:INT ii;
同上,表示定义了一个int类型的变量ii;
同理可得:
typedef void (*Fun)(void);
表示用户自己定义了一个函数指针数据类型 ,该函数指针指向 类似void Foo(void)函数的函数入口地址
Fun pf;
表示定义了一个函数指针pf,该函数指针指向类似于void *pf(void)的函数 //leo