首先VS2015配置:
在当前工程右键 --> 属性:
先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX的内存布局。
开始进入主题测试类对象内存布局:
1. 只有数据成员的对象
成员变量是按照定义的顺序来保存的, 最先声明的在最上边, 然后依次保存.
类对象的大小就是所有成员变量大小之和.
程序输出:
sizeof(Base_1) = 16
内存布局:
1> class Base_1 size(16):
1> +---
1> 0 | base_1_1
1> 4 | base_1_2
1> 8 | base_1_3
测试代码:
#include<iostream>
#include<string>
using namespace std;
class Base_1
{
public:
int base_1_1;/* 4 */
int base_1_2;/* 4 */
long long base_1_3; /* 8 */
};
int main()
{
cout << endl << "1. 只有数据成员的对象" << endl;
cout << "sizeof(Base_1) = " << sizeof(Base_1) << endl << endl;
return 0;
}
2. 有数据成员的对象,并且包含一个普通函数的对象,没有虚函数的对象
可以看到对象的的大小等于成员属性大小之和,普通的成员函数并不产生内存空间,也就不会对对象的布局造成任何影响,
那么他就不可能会发生动态绑定,当调用一个非虚函数时, 那么调用的一定就是当前指针类型拥有的那个成员函数.
这种调用机制在编译时期就确定下来了.
程序输出:
sizeof(Base_1) = 8
内存布局:
1> class Base_1 size(8):
1> +---
1> 0 | base_1_1
1> 4 | base_1_2
1> +---
测试代码:
#include<iostream>
#include<string>
using namespace std;
class Base_1
{
public:
int base_1_1;
int base_1_2;
void Base_1_fun()
{
cout << "void Base_1_fun()" << endl;
}
};
int main()
{
cout << endl << "2. 有数据成员的对象,并且包含一个普通函数的对象,没有虚函数的对象" << endl;
cout << "sizeof(Base_1) = " << sizeof(Base_1) << endl << endl;
return 0;
}
3. 有数据成员的对象,并且包含一个虚函数的对象
base1_1前面多了一个变量 __vfptr(常说的虚函数表vtable指针),
其类型为void**, 这说明它是一个void*指针(注意:不是数组),是一个指向数组的指针.
虚函数指针__vfptr位于所有的成员变量之前定义.
程序输出:
sizeof(Base_1) = 12 (成员属性 + 指向虚函数表的指针)
伪代码:
void* __fun[] = { &Base_1::Base_1_fun_1 };
const void** __vfptr = &__fun[0];
内存布局:
1> class Base_1 size(12):
1> +---
1> 0 | {vfptr}
1> 4 | base_1_1
1> 8 | base_1_2
1> +---
虚函数表:
1> Base_1::$vftable@:
1> | &Base_1_meta
1> | 0
1> 0 | &Base_1::Base_1_fun_1
测试代码:
#include<iostream>
#include<string>
using namespace std;
class Base_1
{
public:
int base_1_1;
int base_1_2;
virtual void Base_1_fun_1()
{
cout << "virtual void Base_1_fun_1()" << endl;
}
};
int main()
{
cout << endl << "3. 有数据成员的对象,并且包含一个虚函数的对象" << endl;
cout << "sizeof(Base_1) = " << sizeof(Base_1) << endl << endl;
return 0;
}
4. 有数据成员的对象,并且包含两个虚函数的对象
通过这次可以看出__vfptr 只是一个指向虚函数表的指针而已。
真正保存对象中虚函数的是虚函数表,而这里的虚函数指针只是提供一个虚函数表的入口。
程序输出:
sizeof(Base_1) = 12 (成员属性 + 指向虚函数表的指针)
伪代码:
void* __fun[] = { &Base_1::Base_1_fun_1, &Base1::Base_1_fun_2 };
const void** __vfptr = &__fun[0];
虚函数表:
1. 同一个类的不同实例共用同一份虚函数表, 它们都通过一个所谓的虚函数表指针__vfptr(定义为void**类型)指向该虚函数表.
2. 它是编译器在编译时期为我们创建好的, 只存在一份
3. 定义类对象时, 编译器自动将类对象的__vfptr指向这个虚函数表
内存布局:
1> class Base_1 size(12):
1> +---
1> 0 | {vfptr}
1> 4 | base_1_1
1> 8 | base_1_2
1> +---
虚函数表:
1> Base_1::$vftable@:
1> | &Base_1_meta
1> | 0
1> 0 | &Base_1::Base_1_fun_1
1> 1 | &Base_1::Base_1_fun_2
测试代码:
#include<iostream>
#include<string>
using namespace std;
class Base_1
{
public:
int base_1_1;
int base_1_2;
virtual void Base_1_fun_1()
{
cout << "virtual void Base_1_fun_1()" << endl;
}
virtual void Base_1_fun_2()
{
cout << "virtual void Base_1_fun_2()" << endl;
}
};
int main()
{
cout << endl << "4. 有数据成员的对象,并且包含两个虚函数的对象" << endl;
cout << "sizeof(Base_1) = " << sizeof(Base_1) << endl << endl;
return 0;
}
未完待续...