小学生学C++编程语法知识(C++类初始化详解(一)) C类初始化详解一很多同学第一次学习类class时会觉得“我创建一个对象不就是给变量赋值吗为什么还要学习构造函数、初始化列表”其实类初始化是C面向对象最重要的基础之一。今天我们解决几个核心问题一个类的成员变量有哪些初始化方式构造函数到底什么时候执行成员变量初始化顺序是什么为什么成员初始化列表更快哪些情况必须使用初始化列表一、先理解什么叫初始化假设我们设计一个学生类class Student { public: string name; int age; };创建对象Student s;现在s ------------- | name | | age | -------------但是name是什么 age是多少不知道。所以我们需要给成员变量一个初始值。这个过程叫初始化Initialization二、类成员初始化的三种方式C中常见有三种方式。方式1创建对象后赋值最简单class Student { public: string name; int age; }; int main() { Student s; s.nameTom; s.age10; }过程第一步创建对象Student s;产生s ------- |name ? | |age ? | -------第二步赋值s.nameTom; s.age10;变成--------- |Tom | |10 | ---------这种方法的问题对象已经出生了然后再修改。类似小孩出生宝宝出生 ↓ 再告诉他名字 ↓ 再告诉他年龄效率低。方式2构造函数内部赋值例如class Student { public: string name; int age; Student() { nameTom; age10; } };使用Student s;执行进入构造函数 nameTom age10结果Student对象 name Tom age 10看起来很好。但是这里隐藏了一个问题。三、重点成员变量其实已经初始化了一次例如class Student { public: string name; Student() { nameTom; } };很多学生认为执行Student s;过程name产生 ↓ nameTom实际上不是。真实过程第一步 string name创建 第二步 name调用默认构造函数 第三步 nameTom也就是说发生了初始化一次 赋值一次例如string第一次name然后nameTom实际上空字符串 ↓ 赋值Tom多了一步。四、方式3成员初始化列表推荐写法class Student { public: string name; int age; Student() : name(Tom), age(10) { } };注意冒号:后面叫成员初始化列表执行过程直接创建name 同时初始化为Tom创建nameTom一步完成。所以构造函数赋值创建 ↓ 默认初始化 ↓ 赋值初始化列表创建 ↓ 直接初始化少了一步。五、用生活例子理解假设你买手机。方法1买一个空手机手机出厂 ↓ 打开 ↓ 安装系统 ↓ 设置名字方法2厂家直接生产手机时 直接装好系统 写好名字当然第二种更快。六、构造函数执行顺序非常重要很多考试喜欢考。例如class A { public: int x; int y; A() { cout构造函数endl; } };创建A a;执行1. 分配空间 2. 初始化成员变量 3. 执行构造函数 4. 对象创建完成重点成员变量初始化发生在构造函数代码执行之前。七、成员初始化顺序是谁决定的很多学生认为A() :x(10),y(20) { }按照x 然后y执行。对吗不一定真正规则按成员变量在类中声明的顺序初始化。例如class A { public: int x; int y; A() :y(20),x(10) { } };很多人认为y先初始化 x后初始化错误实际x先初始化 y后初始化因为类里面int x; int y;顺序决定。记忆初始化列表顺序看列表真正执行顺序看成员声明。八、为什么初始化列表更快我们比较方法1class Student { public: string name; Student() { nameTom; } };过程创建name ↓ 调用string默认构造 ↓ nameTom两步。方法2Student() :name(Tom) { }过程直接调用string有参构造 创建Tom一步。所以初始化列表减少临时对象 额外赋值 资源复制效率更高。九、哪些成员必须使用初始化列表这是重点。1. const成员变量例如class Student { public: const int age; Student() { age10; } };错误为什么因为const变量出生以后不能修改但是age10属于修改。必须Student() :age(10) { }2. 引用成员变量例如class Test { int x; };引用必须绑定对象。不能x10;必须Test(int a) :x(a) { }3. 没有默认构造函数的对象成员例如class Phone { public: Phone(int price) { } };没有Phone()那么下面错误class Person { Phone phone; Person() { } };因为创建Person时必须先创建phone。但是phone不知道怎么创建。解决Person() :phone(1000) { }十、多个成员变量初始化例如class Student { string name; int age; double score; public: Student(string n,int a,double s) :name(n),age(a),score(s) { } };创建Student s(Tom,10,99.5);过程nameTom age10 score99.5十一、父类和成员对象初始化顺序进阶学习继承会遇到。对象出生顺序1. 父类初始化 2. 成员对象初始化 3. 自己成员初始化 4. 构造函数主体例如class Child:public Parent { };创建ChildParent出生 ↓ Child成员出生 ↓ Child构造函数十二、析构函数的顺序对应出生父类 ↓ 成员 ↓ 自己死亡反过来自己析构 ↓ 成员析构 ↓ 父类析构十三、小学生记忆口诀构造函数对象出生自动调用 先成员 后自己初始化列表冒号后面写初始化 比函数里面赋值快 const引用必须用它成员初始化顺序不要看列表排哪里 只看类里声明序十四、竞赛常见考点总结知识点是否常考构造函数自动执行⭐⭐⭐⭐初始化列表语法⭐⭐⭐⭐const成员必须初始化列表⭐⭐⭐⭐⭐引用成员必须初始化列表⭐⭐⭐⭐⭐成员初始化顺序⭐⭐⭐⭐⭐初始化列表效率原因⭐⭐⭐给学生的一句话总结构造函数负责“对象出生时做什么”成员初始化列表负责“对象出生时是什么样”。真正高级的C程序员会尽量让对象一出生就是完整状态而不是出生以后再修改它。