平时做开发使用的语言最多的是c++, class(类)是c++中必不可少的因素,除了熟悉它的用法外,也必须清楚它在内存中的样子,这篇文章就是简要介绍它内存中布局情况.
我们先来看一个简单的类:
class Ex1
{
int var1;
int var2;
char var3;
public:
int get_var1();
};
这个类在内存中是这个样子的:
class Ex1 size(12):
+---
0 | var1
4 | var2
8 | var3
| <alignment member> (size=3)
+---
最后一个类的成员变量后面有3个字节的填充,这是因为要求4字节对齐.在Visual C++中,类的成员变量是按照其声明的大小依次排列在内存中的.
那么, 如果在一个类中含有虚函数呢?
Class Ex2
{
int var1;
public:
virtual int get_sum(int x, int y);
virtual void reset_values();
};
下面是这个类在内存中的存在形式:
class Ex2 size(8):
+---
0 | {vfptr}
4 | var1
+---
注意指向虚函数表的指针(vfptr)是被添加在最前面的,而在虚函数表里面,各个虚函数是按照其声明的顺序排列的. 类Ex2的虚函数表如下:
Ex2::$vftalbe@:
0 | &Ex2::get_sum
4 | &Ex2::reset_values
当一个类是继承另一个类的话,情况又会怎么样呢? 下面讨论一个简单的单一继承关系
Class Ex3:public Ex2
{
int var1;
public:
void get_values();
};
在内存中这个类的情况是这样的:
Class Ex3 size(12);
+----
| +--- (base class Ex2)
0 | | {vfptr}
4 | | var1
| +---
8 | var1
+---
正如您所看到的,派生类只是简单的把基类嵌入到自己内部就完事了.但是万一要是有多重继承会有什么情况发生呢?
Class Ex4
{
int var1;
int var2;
public:
virtual void func1();
virtual void func2();
};
Class Ex5: public Ex2, Ex4
{
int var1;
public:
void func1();
virtual void v_ex5();
};
内存中的情况会是这样:
Class Ex5 size(24):
+---
| +--- (base class Ex2)
0 | | {vfptr}
4 | | var1
| +---
| +--- (base class Ex4)
8 | | {vfptr}
12 | | var1
16 | | var2
| +---
20 | var1
+---
Ex5::$vftalbe@Ex2@:
0 | &Ex2::get_sum
1 | &Ex2::reset_values
2 | &Ex5::v_ex5
Ex5::$vftable@Ex4@:
| -8
0 | &Ex5::func1
1 | &Ex4::func2
派生类将每个基类都嵌入了自己,而且每个基类还都保留有自己的虚函数表.但是请注意,第一个基类的虚函数表是被派生类共享的,派生类的虚函数将会被列在基类虚函数表的后面.另外要注意的是,因为Ex5中也有一个和Ex4中的虚函数同名的func1(), 所以根据C++的规则,Ex4虚函数中的func1()函数的指针已经被Ex5的func1()的函数指针给替换掉了.