C++定义类时不分配内存,类成员及初始值存储在哪?
首先纠正一个初学者很容易踩的认知偏差:你说的「创建对象前系统不会为Car类分配内存」,这里的内存特指存对象运行时数据的栈、堆内存。类的结构定义、成员默认值这类信息,根本不需要在运行时给类单独开栈/堆空间存——这些东西在你编译代码的时候,就被编译器处理完,直接写进最终生成的机器指令里了。
就拿你贴的代码举例:
class Car{ public: string model; bool petrol; int wheels = 4; } int main(){ Car A; cout << A.wheels; return 0; }
你在类里写的int wheels = 4;是C++的默认成员初始化器,编译器看到这段的时候,会自动把「给wheels成员赋值4」的逻辑,塞到它为Car类生成的默认无参构造函数里。除此之外,Car类每个成员在实例内存里的偏移位置——也就是model、petrol、wheels分别从对象内存块的第几个字节开始存——也全是编译阶段就算好固定死的,根本不需要运行时再临时计算。
等程序实际跑起来,执行到Car A;这行的时候,流程非常直白:
- 在当前函数的栈空间里,划出一块大小刚好能存下Car对象的内存,这就是实例A的存储空间
- 自动调用之前编译器生成好的默认构造函数,按照早就写死的指令,找到A这块内存里wheels对应的固定偏移位置,直接把4写进去
- 后面读
A.wheels的时候,直接从这个固定位置读值就行
整个过程根本不需要运行时专门找一块存「Car类专属信息」的内存去查wheels的初始值是多少——给wheels赋4本身就是CPU要执行的一条硬编码指令,这些指令存在程序的代码段(专门存执行指令的只读内存区),程序启动的时候就加载到内存里了,根本不用等创建对象的时候再分配空间、临时读取。
补充个很多人会搞混的点:大家常说「类是创建对象的模板」,很多人就直觉觉得这个模板得和对象一样存在栈/堆里才能用。实际上这个模板的绝大多数信息都被转成了可直接执行的指令,只有用到虚函数、运行时类型识别(RTTI)这类特性的时候,才会在程序的只读数据段存点辅助信息(比如虚表、类型名),这些也是程序启动就加载好的,不属于你理解的「给类分配的实例类内存」。
你要是有空可以把这段代码开O2优化编译成汇编看,会发现编译器直接把cout << A.wheels;优化成了输出常量4,连创建对象、给成员赋值的步骤都给省了——这也能侧面说明,wheels的初始值4根本不需要运行时从什么类的存储空间里读,编译器在编译阶段就已经把这个值摸得一清二楚了。
内容的提问来源于stack exchange,提问作者user16719299

