c++对象模型
首先看这样一个类
class Test{
};
- 在c++中,对于一个空类,c++不允许什么都不存在,会有一个字节的占位空间。
如果类中有成员变量
class Test{
char a[2];
};
- 现在看似很正常
如果类中有函数
class Test{
public:
void fun()
{
}
};
如果类中有虚函数
class Test{
public:
virtual void fun()
{
}
};
- 此时,c++会在类的中产生一个指针,这是一个函数指针,指向虚函数--虚表,因为虚函数要实现一种动态绑定,而其他函数不需要,所以,有虚函数存在的时候,类的对象中会有一个指针来指向所有虚函数。
如果类中有虚函数和成员变量
class Test{
public:
char a[2];
virtual void fun(){}
};
- 按理说
sizeof(Test)
应该是2+8=10,但是却是16,这是因为,此时会发生内存对齐,为了效率,会让内存的大小按照最大的字段的整数倍进行对齐。
验证虚表
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<<"构造"<<endl;
}
virtual ~TestModel(){
cout<<"析构"<<endl;
}
int i;
private:
void myTest(){
cout<<"myTest"<<endl;
}
void my(){
cout<<"my"<<i<<endl;
}
};
对于上面这样一个类,他的内存分布情况如下
+---------+
| 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<<"构造"<<endl;
}
virtual ~TestModel(){
cout<<"析构"<<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;
}
+---------+
| 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)
+-----------------------------+
- 测试代码中,用一个函数指针指向虚表的各个函数,就能调用到对应的函数,说明正确的找到了函数
- 并且通过传入的函数的指针值不同,调用的函数中打印出来的i不同,可以说明
this指针
是在函数调用的时候通过参数传入的