额,今日需要回家了,暂停更新博文一周。以下是之前自己测试过关于类的内存结构的相关分析。
类的内存结构
编译环境:ubuntu系统下eclipse
1. 空类
#include <iostream>
using namespace std;
//说明一个空类的内存占用
class class_t
{
};
int main()
{
class_t obj;
cout << "Size of obj is = " << sizeof(obj) << endl;
cout << "Address of obj is = " << &obj << endl;
while (1);
return 0;
}
输出如下:
Size of obj is = 1
Address of obj is = 0xbfc19e0f
编译器在执行class_t obj;这行代码后需要,作出一个class class_t的Object 。而且这个Object的地址是独一无二的,于是编译器就会给空类创建一个隐含的一个字节的空间。
2. 含成员变量的类
#include <iostream>
using namespace std;
class point_t {
private:
int m_x;
int m_y;
};
int main() {
point_t obj;
cout << "Size of obj is = " << sizeof(obj) << endl;
cout << "Address of obj is = " << &obj << endl;
while (1);
return 0;
}
输出如下:
Size of obj is = 8
Address of obj is = 0xbfaa1c18
对于上述程序,在类定义中加入static T m_z; 输出结果同上,添加了一个静态成员变量,但是Class Size仍然不变。说明静态变量存放在全局/静态区,非静态变量存放在栈上。
加入static void print(),class size也不改变,加入一个函数void display(),class size也是不改变的,说明函数是不占用类空间的。
将int m_y;改为 char m_y;输出结果如下:
Size of obj is = 8
Address of obj is = 0xbfaf2e48
Class size 还是8,编译器为了CPU计算,作出的数据对齐处理。
3. 含虚函数的类
#include <iostream>
using namespace std;
class class_t{
public:
virtual void fun()
{
cout << "Class::fun" << endl; }
};
int main() {
class_t obj;
cout << "Size of obj = " << sizeof(obj) << endl;
cout << "Address of obj = " << &obj << endl;
while (1);
return 0;
}
输出:
Size of obj = 4
Address of obj = 0xbfde8fcc
虚函数表指针占4个字节;但是,对类class_t中再添加几个虚函数,结果还是输出class size 为4,说明虚函表数指针存储了一个虚函数表的地址,其中存储了类中所有虚函数的地址。也就是说,虚函数表是一个数组,这个数组的元素为虚函数指针的地址。
4. 含成员变量与虚函数的类
对3中程序在类中添加如下类成员变量:private:
int m_x;
int m_y;
则输出为:Size of obj = 12
Address of obj = 0xbfef5054
则class size 为成员变量与虚函数所占内存的总和
5. 继承
#include <iostream>
using namespace std;
template <typename T>
class point_t {
public:
T m_x;
T m_y;
};
template <typename T>
class point3d_t : public point_t<T> {
public:
T m_z;
};
int main() {
point_t<int> objPoint;
cout << "Size of object Point is = " << sizeof(objPoint) << endl;
cout << "Address of object Point is = " << &objPoint << endl;
point3d_t<int> objPoint3d;
cout << "Size of object Point3D is = " << sizeof(objPoint3d) << endl;
cout << "Address of object Point3D is = " << &objPoint3d << endl;
while (1);
return 0;
}
输出:
Size of object Point is = 8
Address of object Point is = 0xbfc29168
Size of object Point3D is = 12
Address of object Point3D is = 0xbfc2915c
派生类所占据的内存为它本身的数据成员和它基类的成员之和。
#include <iostream>
using namespace std;
class base1_t {
public:
virtual void f() { }
};
class base2_t {
public:
virtual void f() { }
};
class base3_t {
public:
virtual void f() { }
};
class drive_t : public base1_t, public base2_t, public base3_t {
};
int main() {
drive_t obj;
cout << "Size of obj is = " << sizeof(obj) << endl;
while (1);
return 0;
}
输出:
Size of obj is = 12
当从多个基类继承一个类的时候,这个派生类就会拥有所有基类的虚函数表指针。所以对于类drive_t共有三个虚函数表指针。
当对以上各类中都加入一个整型成员变量时,结果为28,说明派生类的所占据的内存为它本身的数据成员和它基类的成员之和16,派生类就会拥有所有基类的虚函数表指针,占12。
即使在类drive_t中加入另外的虚函数,结果也不变,如下:
#include <iostream>
using namespace std;
class base1_t {
virtual void f() { cout << "Base1::f" << endl; }
virtual void g() { cout << "Base1::g" << endl; }
};
class base2_t {
virtual void f() { cout << "Base2::f" << endl; }
virtual void g() { cout << "Base2::g" << endl; }
};
class base3_t {
virtual void f() { cout << "Base3::f" << endl; }
virtual void g() { cout << "Base3::g" << endl; }
};
class drive_t : public base1_t, public base2_t, public base3_t {
public:
virtual void fd() { cout << "Drive::fd" << endl; }
virtual void gd() { cout << "Drive::gd" << endl; }
};
typedef void(*Fun)(void);
int main() {
drive_t objDrive;
Fun pFun = NULL;
// 调用Base1的第一个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+0)+0);
pFun();
// 调用Base1的第二个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+0)+1);
pFun();
// 调用Base2的第一个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+1)+0);
pFun();
// 调用Base2的第二个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+1)+1);
pFun();
// 调用Base3的第一个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+2)+0);
pFun();
// 调用Base3的第二个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+2)+1);
pFun();
// 调用派生类的第一个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+0)+2);
pFun();
// 调用派生类的第二个虚函数
pFun = (Fun)*((int*)*(int*)((int*)&objDrive+0)+3);
pFun();
while (1);
return 0;
}
输出:
Base1::f
Base1::g
Base2::f
Base2::g
Base3::f
Base3::g
Drive::fd
Drive::gd
说明多重继承时,派生类的虚函数放在第一个父类的虚函数表中,自己不需要再有虚函数表指针,所以上个程序即使在类drive_t中加入另外的虚函数,class size 也不改变。
6. 虚函数与成员变量的内存分配
#include <iostream>
using namespace std;
class point_t {
public:
int m_ix;
int m_iy;
point_t(const int p_ix = 0, const int p_iy = 0) :
m_ix(p_ix), m_iy(p_iy) {
}
int get_x() const {
return m_ix;
}
int get_y() const {
return m_iy;
}
virtual ~point_t() { }
};
int main() {
point_t objPoint(5, 10);
int* pInt = (int*)&objPoint;
*(pInt + 0) = 100; // 改变x的值
*(pInt + 1) = 200; // 改变y的值
cout<<"Size of point_t is = "<<sizeof(objPoint)<<endl;
cout<<"Address of point_t is = "<<&objPoint<<endl;
cout << "X = " << objPoint.get_x() << endl;
cout << "Y = " << objPoint.get_y() << endl;
while(1);
return 0;
}
输出:
Size of point_t is = 12
Address of point_t is = 0xbfc40300
X = 200
Y = 10
Class size 为12,即为两个int型成员变量与一个虚析构函数,共12字节。
而把 *(pInt + 0) = 100; // 改变x的值
*(pInt + 1) = 200; // 改变y的值
改为: *(pInt + 1) = 100; // 改变x的值
*(pInt + 2) = 200; // 改变y的值
则输出为:
Size of point_t is = 12
Address of point_t is = 0xbff063b0
X = 100
Y = 200
说明虚函数表指针就会被添加在存放该类的内存区域中的第一个位置。成员变量分配在后继的位置。