本文主要是介绍[面试经]VPTR和VTBL,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
假设是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 bint* 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 VPTRcout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl;Fun pFun = (Fun)*(int*)*(int*)(&obj+0); // calling Virtual functionpFun();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 functionscout << "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 functionpFun = (Fun)*((int*)*(int*)(&obj+0)+0);pFun();// calling 2nd virtual functionpFun = (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 Base1pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);pFun();// calling 2nd virtual function of Base1pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);pFun();// calling 1st virtual function of Base2pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);pFun();// calling 2nd virtual function of Base2pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);pFun();// calling 1st virtual function of Base3pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);pFun();// calling 2nd virtual function of Base3pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);pFun();// calling 1st virtual function of DrivepFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);pFun();// calling 2nd virtual function of DrivepFun = (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
这篇关于[面试经]VPTR和VTBL的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!