小学生学C++编程语法知识(C++类初始化详解(二))
C++类对象的创建过程
从内存分配 → 成员初始化 → 构造函数 → 析构函数全过程
目标:
理解“对象出生”的全过程
理解构造函数为什么自动执行
理解初始化列表为什么重要
理解析构函数什么时候执行
为后面学习继承、多态、虚函数打基础
一、先问一个问题:
我们写:
Student s;到底发生了什么?
很多初学者认为:
“调用构造函数,然后对象产生。”
其实不完整。
真正过程非常复杂:
Student s; ↓ 1. 给对象分配内存 ↓ 2. 初始化成员变量 ↓ 3. 执行构造函数 ↓ 4. 对象正式出生二、准备一个例子
我们定义一个学生类:
#include<iostream> using namespace std; class Student { public: string name; int age; Student() { cout<<"构造函数执行"<<endl; } ~Student() { cout<<"析构函数执行"<<endl; } };main:
int main() { Student s; }运行:
输出:
构造函数执行 析构函数执行为什么?
我们一步一步分析。
三、第一步:给对象分配内存
执行:
Student s;系统首先:
找到一块内存。
例如:
栈空间 +----------------+ | | | Student对象 | | | +----------------+假设:
string name; int age;需要空间:
Student对象 +-------------+ | name | | age | +-------------+此时:
对象只是一个“空盒子”。
注意:
这时候:
构造函数还没有执行!
四、第二步:初始化成员变量
接下来:
初始化:
name age对于:
string name;调用:
string默认构造函数产生:
name=""对于:
int age;如果没有初始化:
普通局部变量:
age 里面是随机值例如:
age=32768所以:
此时:
Student对象 +-------------+ | name="" | | age=? | +-------------+五、第三步:执行构造函数
现在:
进入:
Student() { cout<<"构造函数执行"; }输出:
构造函数执行如果里面写:
Student() { name="Tom"; age=10; }那么:
执行:
name="Tom" age=10最终:
Student +-------------+ | Tom | | 10 | +-------------+六、第四步:对象出生完成
此时:
对象才真正可以使用。
例如:
cout<<s.name;可以访问。
所以完整流程:
Student s; ① 分配内存 ② 初始化成员 ③ 执行构造函数 ④ 对象创建完成七、为什么构造函数不是第一步?
很多孩子会问:
“为什么不先执行构造函数?”
原因:
构造函数也是一个函数。
函数执行时:
需要对象已经存在。
比如:
Student() { age=10; }这里:
age必须已经有空间。
否则:
你给谁赋值?
所以:
必须:
先有房子 ↓ 再装修房子八、成员初始化列表在哪里执行?
我们看:
class Student { string name; int age; public: Student() :name("Tom"),age(10) { } };执行过程:
不是:
创建对象 ↓ 进入构造函数 ↓ 执行冒号错误!
真实:
分配内存 ↓ 初始化name (name直接变Tom) ↓ 初始化age (age直接变10) ↓ 进入构造函数{}也就是说:
初始化列表发生在:
构造函数函数体之前。
九、构造函数里面有什么?
构造函数分两部分:
例如:
Student() :name("Tom"),age(10) { cout<<"hello"; }分为:
第一部分:
初始化列表:
:name("Tom"),age(10)负责:
出生状态第二部分:
函数体:
{ }负责:
出生以后做事情类似:
孩子出生:
初始化:
姓名 年龄 性别构造函数:
哭 睁眼 吃奶十、对象什么时候死亡?
看:
int main() { Student s; }程序运行:
进入main:
Student出生执行:
构造函数然后:
main结束:
Student死亡执行:
析构函数输出:
构造函数执行 析构函数执行十一、析构函数是什么?
析构函数:
名字:
~类名()例如:
~Student() { }作用:
对象消失之前,负责清理工作。
比如:
对象里面申请了空间:
int *p; p=new int[100];对象死亡时:
需要:
delete []p;否则:
内存泄漏。
十二、对象死亡顺序
如果:
int main() { Student a; Student b; }出生:
a出生 ↓ b出生死亡:
反过来:
b死亡 ↓ a死亡口诀:
谁后出生,谁先死亡。
十三、多个成员对象的创建顺序
看:
class Engine { public: Engine() { cout<<"发动机"<<endl; } }; class Car { Engine e; public: Car() { cout<<"汽车"<<endl; } };创建:
Car c;输出:
发动机 汽车为什么?
因为:
汽车里面有发动机。
必须:
先制造发动机 ↓ 再制造汽车全过程:
Car对象分配空间 ↓ Engine成员初始化 ↓ Car构造函数十四、继承情况下更复杂
例如:
class Animal { public: Animal() { cout<<"动物"<<endl; } }; class Dog:public Animal { public: Dog() { cout<<"狗"<<endl; } };创建:
Dog d;输出:
动物 狗为什么?
因为:
狗继承动物。
出生:
必须:
先有父亲 ↓ 再有孩子十五、完整生命周期图
一个对象的一生:
创建对象 ↓ 分配内存 ↓ 初始化成员 ↓ 执行构造函数 ↓ 对象工作 ↓ 离开作用域 ↓ 执行析构函数 ↓ 释放内存十六、C++对象生命周期口诀
同学们记:
出生:
先分配 再初始化 最后构造消亡:
先析构 再释放初始化:
列表先执行 函数体后执行十七、竞赛常考点总结
| 知识点 | 重要程度 |
|---|---|
| 构造函数自动调用 | ⭐⭐⭐⭐⭐ |
| 析构函数自动调用 | ⭐⭐⭐⭐ |
| 成员初始化顺序 | ⭐⭐⭐⭐⭐ |
| 初始化列表执行时机 | ⭐⭐⭐⭐⭐ |
| 对象局部变量生命周期 | ⭐⭐⭐⭐ |
| 父类、成员、自己的构造顺序 | ⭐⭐⭐⭐⭐ |
十八、给同学们总结
可以把对象想象成一个小机器人:
制造机器人 ↓ 安装零件 ↓ 开机初始化 ↓ 执行启动程序 ↓ 工作 ↓ 关机清理 ↓ 报废对应C++:
分配内存 ↓ 成员初始化 ↓ 构造函数 ↓ 对象使用 ↓ 析构函数 ↓ 释放资源