C++ 类的内存布局
基类类内成员的内存分布
常见类内成员大致分为:类内变量、类内函数、静态变量、虚函数等,内存分布遵循:
- 所有成员会按照声明的顺序布局
- 类内成员会进行大对齐
- 类内函数不占用类的内存,存储在代码区
- 静态变量不占用类的内存,存储在全局/静态区
- 所有虚函数共用一个虚函数表指针,虚函数表指针不按声明顺序布局,如果有声明虚函数则虚函数表指针始终在类的内存地址的开始
例如:
#include <iostream>
using namespace std;
class Base {
public:
short baseShort;
int baseInt;
char baseChar;
const double baseConst;
static int baseStaticInt;
static const double baseStaticConst;
virtual void baseFunc1() {}
virtual void baseFunc2() {}
Base() : baseConst(0.0) {} // 在构造函数中初始化 baseConst
};
int Base::baseStaticInt = 0; // 静态成员变量的定义
const double Base::baseStaticConst = 0.0; // 静态成员常量的定义
int main() {
Base b;
cout << "Size of Base class: " << sizeof(Base) << " bytes" << endl;
// 计算偏移量
cout << "Offset of baseShort: " << (char*)&b.baseShort - (char*)&b << endl;
cout << "Offset of baseInt: " << (char*)&b.baseInt - (char*)&b << endl;
cout << "Offset of baseChar: " << (char*)&b.baseChar - (char*)&b << endl;
cout << "Offset of baseConst: " << (char*)&b.baseConst - (char*)&b << endl;
cout << "Offset of baseStaticInt: " << (char*)&Base::baseStaticInt - (char*)&b << endl;
cout << "Offset of baseStaticConst: " << (char*)&Base::baseStaticConst - (char*)&b << endl;
return 0;
}
运行结果为:
Size of Base class: 32 bytes
Offset of baseShort: 8
Offset of baseInt: 12
Offset of baseChar: 16
Offset of baseConst: 24
Offset of baseStaticInt: -140725407776668
Offset of baseStaticConst: -140725409879624
可以看出编译器将变量进行了适当对齐,而静态成员变量并不位于类的内存中。
派生类类内成员的内存分布
当出现继承时,如果没有虚函数,则基类的内存地址位于派生类的起始地址;如果有虚函数,则虚函数表指针位于派生类的起始地址,其余变量按继承顺序按序分布。
例如:
#include <iostream>
using namespace std;
class Base {
public:
short baseShort;
int baseInt;
char baseChar;
const double baseConst;
static int baseStaticInt;
static const double baseStaticConst;
virtual void baseFunc1() {}
virtual void baseFunc2() {}
Base() : baseConst(0.0) {} // 在构造函数中初始化 baseConst
};
int Base::baseStaticInt = 0; // 静态成员变量的定义
const double Base::baseStaticConst = 0.0; // 静态成员常量的定义
class Derived : public Base {
public:
double derivedDouble;
static int derivedStaticInt;
static const double derivedStaticConst;
virtual void derivedFunc1() {}
virtual void derivedFunc2() {}
};
int Derived::derivedStaticInt = 0; // 静态成员变量的定义
const double Derived::derivedStaticConst = 0.0; // 静态成员常量的定义
int main() {
Base b;
Derived d;
cout << "Size of Base class: " << sizeof(Base) << " bytes" << endl;
cout << "Size of Derived class: " << sizeof(Derived) << " bytes" << endl;
// 计算偏移量
cout << "Offset of baseShort: " << (char*)&b.baseShort - (char*)&b << endl;
cout << "Offset of baseInt: " << (char*)&b.baseInt - (char*)&b << endl;
cout << "Offset of baseChar: " << (char*)&b.baseChar - (char*)&b << endl;
cout << "Offset of baseConst: " << (char*)&b.baseConst - (char*)&b << endl;
cout << "Offset of baseStaticInt: " << (char*)&Base::baseStaticInt - (char*)&b << endl;
cout << "Offset of baseStaticConst: " << (char*)&Base::baseStaticConst - (char*)&b << endl;
cout << "Offset of derivedDouble: " << (char*)&d.derivedDouble - (char*)&d << endl;
cout << "Offset of derivedStaticInt: " << (char*)&Derived::derivedStaticInt - (char*)&d << endl;
cout << "Offset of derivedStaticConst: " << (char*)&Derived::derivedStaticConst - (char*)&d << endl;
cout << "Offset of baseShort in Derived: " << (char*)&b.baseShort - (char*)&b << endl;
cout << "Offset of baseInt in Derived: " << (char*)&d.baseInt - (char*)&d << endl;
cout << "Offset of baseChar in Derived: " << (char*)&d.baseChar - (char*)&d << endl;
cout << "Offset of baseConst in Derived: " << (char*)&d.baseConst - (char*)&d << endl;
cout << "Offset of baseStaticInt in Derived: " << (char*)&Base::baseStaticInt - (char*)&d << endl;
cout << "Offset of baseStaticConst in Derived: " << (char*)&Base::baseStaticConst - (char*)&d << endl;
return 0;
}
运行结果为:
Size of Base class: 32 bytes
Size of Derived class: 40 bytes
Offset of baseShort: 8
Offset of baseInt: 12
Offset of baseChar: 16
Offset of baseConst: 24
Offset of baseStaticInt: -140726083185396
Offset of baseStaticConst: -140726085287800
Offset of derivedDouble: 32
Offset of derivedStaticInt: -140726083185344
Offset of derivedStaticConst: -140726085287744
Offset of baseShort in Derived: 8
Offset of baseInt in Derived: 12
Offset of baseChar in Derived: 16
Offset of baseConst in Derived: 24
Offset of baseStaticInt in Derived: -140726083185348
Offset of baseStaticConst in Derived: -140726085287752