目录
一、类的实例化详解
1、什么是类的实例化?
-
类实例化是指用类类型在物理内存中创建对象的过程
-
类是对对象的一种抽象描述,是一种模型或蓝图
-
类限定了成员变量和成员函数,但这些只是声明,不会分配实际内存空间
2、关键概念
类如同模型或蓝图
-
类定义仅规定了类包含哪些成员(属性和方法)
-
定义类时并不会分配实际的内存空间
-
类似于C语言中定义结构体类型但不创建变量
实例化创建实际对象
-
一个类可以实例化出多个对象,每个对象都是独立的实体,互不干扰
-
只有在实例化对象时,系统才会为成员变量分配实际的物理内存空间
-
每个对象占用独立的物理内存空间存储其成员变量
-
类似于用结构体类型创建变量时分配实际内存
现实类比

类实例化对象就像使用建筑设计图建造房子:
-
类相当于设计图:规划了房间数量、大小和功能,图纸本身(类)没有实体存在
-
实例化就是根据图纸建造实际的房子
-
对象相当于实际建造的房子,只有建造出的房子(对象)才占用物理空间:可以实际使用和居住
-
设计图(类)本身不能住人,只有建好的房子(对象)才能住人
2、代码示例
cpp
#include<iostream>
using namespace std;
class Date {
public:
// 初始化日期
void Init(int year, int month, int day) {
_year = year;
_month = month;
_day = day;
}
// 打印日期
void Print() {
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
// 这里只是声明成员变量,没有实际分配空间
int _year;
int _month;
int _day;
};
int main() {
// Date类实例化出对象d1和d2
Date d1; // 第一个Date对象
Date d2; // 第二个Date对象
// 初始化并打印d1
d1.Init(2024, 3, 31);
d1.Print();
// 初始化并打印d2
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}
示例说明
-
类定义阶段:
-
Date
类定义了三个私有成员变量(_year
,_month
,_day
) -
此时只是声明,没有分配内存空间
-
-
实例化阶段:
-
Date d1
和Date d2
语句实际创建了两个Date对象 -
此时系统为每个对象分配独立的内存空间来存储其成员变量
-
-
对象使用:
-
每个对象可以独立调用成员函数(
Init()
和Print()
) -
对象之间的数据互不干扰(d1和d2存储不同的日期值)
-
3、重要结论(重要!!!)
-
类定义只是描述了对象的结构和行为
-
只有实例化后才会为对象分配内存,才能实际使用类的功能
-
每个对象都有自己独立的成员变量存储空间,每个对象都有自己独立的状态(成员变量值)
-
类的方法(成员函数)被所有对象共享,不占用对象的内存空间
-
类是抽象的模板,对象是具体的实例
理解类的实例化是面向对象编程的基础,它体现了"抽象"与"具体"的关系。
二、类对象模型与内存布局详解
1、类对象的内存结构(重要!!!)
类对象在内存中的存储方式遵循以下原则:
成员变量存储
-
每个对象独立存储自己的成员变量
-
不同对象的成员变量值互不影响
-
成员变量按照结构体内存对齐规则排列
成员函数存储
-
所有对象共享同一份成员函数代码
-
成员函数存储在公共代码区,不占用对象的内存空间
-
成员函数编译后成为指令代码,存储在代码段(公共代码区)
-
对象中不存储成员函数指针(避免重复存储浪费空间)
-
函数调用地址在编译链接时确定,运行时直接通过固定地址调用
存储效率考量
-
若存储函数指针,100个对象将重复存储100次相同指针
-
实际只需在代码段保存一份函数实现,所有对象共享
2、类对象存储模型图示

3、类大小计算规则
基本规则
-
类大小等于其所有非静态成员变量大小之和(考虑内存对齐)
-
静态成员变量不占用类对象空间(存储在全局区)
-
成员函数不占用类对象空间
特殊类大小说明
-
空类大小:
-
大小为1字节(编译器分配的占位标识,确保对象有唯一地址)
-
示例:
class C{};
→ 1字节
-
-
仅有成员函数的类:
-
大小同样为1字节
-
示例:
class B{void Print(){}};
→ 1字节
-
-
含成员变量的类:
-
大小为成员变量总和(考虑对齐)
-
示例:
class A{char _ch; int _i;};
→ 8字节(1+3填充+4)
-
4、验证示例
cpp
#include <iostream>
using namespace std;
class Person
{
public:
void ShowInfo()
{
cout << _name << "-" << _sex << "-" << _age << endl;
}
public:
char *_name; // 姓名 (指针类型,通常4/8字节)
char *_sex; // 性别 (指针类型,通常4/8字节)
int _age; // 年龄 (通常4字节)
};
// 测试类
class A1
{
public:
void f1() {}
private:
int _a;
};
class A2
{
public:
void f2() {}
};
class A3
{
};
int main()
{
cout << "Person size: " << sizeof(Person) << endl; // 通常12/24字节(取决于指针大小)
cout << "A1 size: " << sizeof(A1) << endl; // 4 (int)
cout << "A2 size: " << sizeof(A2) << endl; // 1 (只有成员函数)
cout << "A3 size: " << sizeof(A3) << endl; // 1 (空类)
return 0;
}

类Person的对象内存布局:

5、结构体内存对齐规则详解
基本规则
- 第一个成员变量位于偏移量0处
- 后续成员对齐到min(成员大小, 编译器默认对齐数)的整数倍地址
- 结构体总大小为最大对齐数的整数倍
VS编译器默认值
- 默认对齐数为8字节
- 实际对齐数取成员大小和默认对齐数的较小值
嵌套结构体规则
- 嵌套结构体对齐到其自身最大对齐数的整数倍处
- 整体大小是所有最大对齐数(含嵌套结构体)的整数倍
对齐示例
cpp
struct Example {
char a; // 1字节,偏移0
// 3字节填充(因为int要对齐到4)
int b; // 4字节,偏移4
short c; // 2字节,偏移8
// 2字节填充(总大小需为4的整数倍)
}; // 总大小:12字节
6、重要结论
-
对象只存储成员变量,成员函数存储在公共代码区(代码段)
-
类大小计算只考虑成员变量,需遵循内存对齐规则,可能包含填充字节
-
空类有1字节占位符,保证每个对象有唯一地址,仅有成员函数的类大小也为1字节(占位标识)
-
内存对齐能提高CPU访问效率,但可能增加空间开销(内存对齐牺牲部分空间换取CPU访问效率提升)
-
实际开发中应注意类成员排列顺序以优化内存使用