c++對象模型
首先看這樣一個(gè)類
class Test{
};
TestSize.png
- 在c++中,對于一個(gè)空類,c++不允許什么都不存在肺孤,會有一個(gè)字節(jié)的占位空間替蛉。
如果類中有成員變量
class Test{
char a[2];
};
TestSizeChar.png
- 現(xiàn)在看似很正常
如果類中有函數(shù)
class Test{
public:
void fun()
{
}
};
TestSize.png
如果類中有虛函數(shù)
class Test{
public:
virtual void fun()
{
}
};
TestSizeVirtual.png
- 此時(shí)谷遂,c++會在類的中產(chǎn)生一個(gè)指針,這是一個(gè)函數(shù)指針,指向虛函數(shù)--虛表,因?yàn)樘摵瘮?shù)要實(shí)現(xiàn)一種動態(tài)綁定挤渔,而其他函數(shù)不需要,所以风题,有虛函數(shù)存在的時(shí)候判导,類的對象中會有一個(gè)指針來指向所有虛函數(shù)嫉父。
如果類中有虛函數(shù)和成員變量
class Test{
public:
char a[2];
virtual void fun(){}
};
TestSizeVirtualChar.png
- 按理說
sizeof(Test)
應(yīng)該是2+8=10,但是卻是16眼刃,這是因?yàn)槿葡剑藭r(shí)會發(fā)生內(nèi)存對齊,為了效率擂红,會讓內(nèi)存的大小按照最大的字段的整數(shù)倍進(jìn)行對齊仪际。
驗(yàn)證虛表
class TestModel{
public:
virtual void test(){
cout<<"this="<<this<<endl;
cout<<"test"<<endl;
my();
}
virtual void test1(){
cout<<"this="<<this<<endl;
cout<<"test1"<<endl;
myTest();
}
TestModel(){
cout<<"構(gòu)造"<<endl;
}
virtual ~TestModel(){
cout<<"析構(gòu)"<<endl;
}
int i;
private:
void myTest(){
cout<<"myTest"<<endl;
}
void my(){
cout<<"my"<<i<<endl;
}
};
對于上面這樣一個(gè)類,他的內(nèi)存分布情況如下
+---------+
| other |---> 其他字段
|---------|
| vptr |---> 虛表 ------->
+---------+ +-----------------------------+
0| test(TestModel* this) |
|-----------------------------|
1| test1(TestModel* this) |
|-----------------------------|
2| ~TestModel(TestModel* this)|
+-----------------------------+
測試代碼
#include <iostream>
#include <stdio.h>
using namespace std;
class TestModel{
public:
virtual void test(){
cout<<"this="<<this<<endl;
cout<<"test"<<endl;
my();
}
virtual void test1(){
cout<<"this="<<this<<endl;
cout<<"test1"<<endl;
myTest();
}
TestModel(){
cout<<"構(gòu)造"<<endl;
}
virtual ~TestModel(){
cout<<"析構(gòu)"<<endl;
}
int i;
private:
void myTest(){
cout<<"myTest"<<endl;
}
void my(){
cout<<"my"<<i<<endl;
}
};
typedef void (*Fun)(void* self);
void fun(){
cout<<"fun"<<endl;
}
int main(int argc, char const *argv[])
{
TestModel a;
TestModel b;
a.i=0;
b.i=1;
int64_t* pa = (int64_t*)&a;
int64_t* pb = (int64_t*)&b;
void* p1;
printf("指針大小%d\n",sizeof(void*));
printf("a的地址%p\n",pa);
printf("a的虛表地址%p\n",*pa);
printf("b的地址%p\n",pb);
printf("b的虛表地址%p\n",*pa);
Fun funp;
funp = (Fun)(*((int64_t*)(*(pa))));
funp(pa);
funp = (Fun)(*((int64_t*)(*(pa))+1));
funp(NULL);
funp = (Fun)(*((int64_t*)(*(pa))+2));
funp(pa);
return 0;
}
TestSizeMain.png
+---------+
| vptr |---> 虛表 -------> <---*pa==*pb
|---------| +-----------------------------+
| other | 0| test(TestModel* this) | *((int64_t*)(*(pa)))
+---------+ |-----------------------------|
1| test1(TestModel* this) | *((int64_t*)(*(pa))+1)
|-----------------------------|
2| ~TestModel(TestModel* this)| *((int64_t*)(*(pa))+2)
+-----------------------------+
- 測試代碼中篮条,用一個(gè)函數(shù)指針指向虛表的各個(gè)函數(shù),就能調(diào)用到對應(yīng)的函數(shù)吩抓,說明正確的找到了函數(shù)
- 并且通過傳入的函數(shù)的指針值不同涉茧,調(diào)用的函數(shù)中打印出來的i不同,可以說明
this指針
是在函數(shù)調(diào)用的時(shí)候通過參數(shù)傳入的