目录
引出:对象在被编译器创建出来时,编译器给对象开辟好空间,那么对象中的成员变量是何时被定义的呢?编译器在创建对象时,会自动调用构造函数,调用构造函数的本质是什么?
- class Time
- {
- public:
- //显示定义一个有参的构造函数,运行报错
- Time(int hour)
- {
- _hour = hour;
- }
- //显式定义一个全缺省的默认构造函数,运行可以通过
- //Time(int hour = 0)
- //{
- // _hour = hour;
- // cout << "调用Time全缺省构造" << endl;
- //}
- private:
- int _hour;
- };
- class Date
- {
- public:
- Date(int year, int month, int day, int hour)
- {
- _year = year;
- _month = month;
- _day = day;
- Time t(hour);
- _t = t;
- }
- private:
- int _year;
- int _month;
- int _day;
- Time _t;
- };
- int main()
- {
- Date d1(2022, 8, 10, 24);
- return 0;
- }
结果:报错
默认构造分三类:编译器生成,显式定义无参,显式定义全缺省
这里报错的原因:Date的构造函数对于内置类型不做处理,对于自定义类型调用其自己的默认构造函数,可以看到,由于Time类中我们显示写了有参构造,编译器就不会生成,自然就没有默认构造。如果我们用int hour = 0这样全缺省的构造就可以被调用了并且调用之后是我们想要的结果。
通过这一现象,可以进一步思考,为什么一定要调用默认构造?我显示定义的有参构造难道不可以直接调用吗?这时需要引出初始化列表这一概念。回到了最开始的问题,对象内的成员变量究竟是何时被定义的?
Time的全缺省构造是被调用了两次的。因为Time的全缺省构造既是默认构造,又是有参构造。
这里就解释了为什么一定要调用默认构造!每个构造函数都隐式的拥有一个初始化列表,而对象内的成员变量就是在初始化列表中被定义的!
以上这里的调用逻辑是:
---> 编译器先创建一个Date类的对象d1,编译器自动调用Date构造函数
这时(构造函数对内置类型不处理,对自定义类型调用自己的默认构造函数)本质就是在初始化列表中给定义的成员变量初始化,由于我们不显式的去写的话,也就没有参数,只能是隐式的调用默认构造函数,也就不需要参数。
---> 初始化列表调用一次默认构造函数(也就是Time的全缺省构造)
---> 之后在Time t(hour)时,再调用一次Time全缺省构造
可以看到对于自定义类型的成员变量类内初始化时:
1.会调用两次构造 + 一次拷贝
(一次在初始化列表调用,一次在创建临时变量调用,一次临时变量的拷贝)
2.自定义类型一定要有自己的默认构造
3.代码过于繁琐
对于以上的总结:
1.初始化列表可以认为是成员变量定义的地方
2.类内初始化成员变量,其实严格意义上不是初始化而是赋值,因为成员变量在初始化列表被定义,被定义的同时也就被初始化了。
3.对于内置类型在哪里初始化都行,对于自定义类型推荐使用初始化列表
- class Time
- {
- public:
- Time(int hour)
- {
- _hour = hour;
- }
- private:
- int _hour;
- };
- class Date
- {
- public:
- Date(int year, int month, int day, int hour)
- :_year(year),_month(month),_day(day),_t(hour)
- {
-
- }
-
- private:
- int _year;
- int _month;
- int _day;
- Time _t;
- };
- int main()
- {
- Date d1(2022, 8, 10, 24);
- return 0;
- }
注意:
1.每个变量只能在初始化列表出现一次
2.以下成员必须在初始化列表初始化
引用成员变量
const成员变量
自定义类型成员变量(没有默认构造时)
引用与const成员变量有一个共同特点:必须在变量定义的地方初始化!而不能定义之后再赋值!
而自定义类型成员变量在初始化列表隐式定义时必须调用默认构造
3.成员变量定义的顺序不是初始化列表中的顺序,而是在类中声明的顺序
4.由于C++默认构造对于内置类型不做处理而有可能导致为随机值,之后打了一个补丁,在变量声明的地方可以加缺省值,这个补丁的本质就是在初始化列表给内置类型加上默认值