c++类常用默认成员函数细节分析
文章目录
- 一、学习目标
- 二、构造函数
- 三、拷贝构造函数
- 四、赋值运算函数
- 五、析构函数
- 六、相互关系
一、学习目标
1.当我们不写,编译器会自动生成这些默认成员函数
2.编译器自动生成的默认成员函数的行为是什么,是否满足我们的需求
3.如果不满足我们的需求我们该如何编写
二、构造函数
1.编译器默认生成的构造函数,自带初始化列表,所有的工作均在初始化列表中完成
(1)对于内置类型成员变量:
a.拥有缺省值:在初始化列表中使用缺省值进行初始化
b.未拥有缺省值:初始化列表对其的行为是未定义的,取决于编译器的实现
(2)对于自定义类型的成员变量:
a.拥有缺省值:使用缺省值调用该自定义类型对应的构造函数进行初始化
b.未拥有缺省值:在初始化列表中调用该自定义类型的默认构造函数进行初始化
如果该自定义类型没有默认构造函数,那么就会报错
(3)对于基类/父类部分
调用基类/父类的默认构造函数
如果基类/父类没有默认构造函数,那么就会报错
2.自己显示定义了构造函数
(1)显示定义了初始化列表(全部的成员变量都在初始化列表)
内置类型,自定义类型,基类/父类全部根据初始化列表的内容和操作进行初始化
当初始化列表中显示初始化该成员变量,那么该成员变量就与缺省值无关了
(2)部分成员变量不在初始化列表或没有显示定义初始化列表
a.对于内置类型成员变量:
拥有缺省值:在初始化列表中使用缺省值进行初始化
未拥有缺省值:初始化列表对其的行为是未定义的,取决于编译器的实现
b.对于自定义类型的成员变量:
拥有缺省值:使用缺省值调用该自定义类型对应的构造函数进行初始化
未拥有缺省值:在初始化列表中调用该自定义类型的默认构造函数进行初始化
如果该自定义类型没有默认构造函数,那么就会报错
c.对于基类/父类部分
调用基类/父类的默认构造函数
如果基类/父类没有默认构造函数,那么就会报错
(3)定义了构造函数,编译器将不再自动生成默认构造,但是还会生成拷贝构造函数
三、拷贝构造函数
1.编译器自动生成的拷贝构造函数
自带初始化列表,对成员变量的行为都是在初始化列表当中完成
该初始化列表无视缺省值
(1)对于内置类型的成员变量
浅拷贝/值拷贝
(2)对于自定义类型的成员变量
调用自定义类型的默认构造函数
如果没有默认构造函数就会报错
(3)对于基类/父类
调用基类/父类的默认构造函数
如果没有默认构造函数就会报错
2.显示定义拷贝构造函数
(1)在初始化列表中的成员变量
根据初始化列表的内容和操作进行初始化
当初始化列表中显示初始化该成员变量,那么该成员变量就与缺省值无关了
(2)不在初始化列表当中的成员变量
a.对于内置类型成员变量:
拥有缺省值:在初始化列表中使用缺省值进行初始化
未拥有缺省值:初始化列表对其的行为是未定义的,取决于编译器的实现
b.对于自定义类型的成员变量:
拥有缺省值:使用缺省值调用该自定义类型对应的构造函数进行初始化
未拥有缺省值:在初始化列表中调用该自定义类型的默认构造函数进行初始化
如果该自定义类型没有默认构造函数,那么就会报错
c.对于基类/父类部分
调用基类/父类的默认构造函数
如果基类/父类没有默认构造函数,那么就会报错
(3)未定义初始化列表
a.对于内置类型成员变量:
拥有缺省值:在初始化列表中使用缺省值进行初始化
未拥有缺省值:初始化列表对其的行为是未定义的,取决于编译器的实现
b.对于自定义类型的成员变量:
拥有缺省值:使用缺省值调用该自定义类型对应的构造函数进行初始化
未拥有缺省值:在初始化列表中调用该自定义类型的默认构造函数进行初始化
如果该自定义类型没有默认构造函数,那么就会报错
c.对于基类/父类部分
调用基类/父类的默认构造函数
如果基类/父类没有默认构造函数,那么就会报错
3.显示定义了拷贝构造函数,无论是否显示定义了构造函数,编译器都不再生成默认构造
四、赋值运输算符重载函数
1.编译器默认生成的赋值运算符重载函数
(1)对于内置类型的成员变量
浅拷贝/值拷贝
(2)对于自定义类型的成员变量
调用自定义类型的赋值运算符重载函数
(3)对于基类/父类
调用基类/父类的赋值运算符重载函数
2.显示定义的赋值运算符重载函数
(1)对于内置类型的成员变量
自己定义行为
(2)对于自定义类型的成员变量
手动调用自定义类型的赋值运算符重载函数
(3)对于基类/父类
手动调用基类/父类的赋值运算符重载函数
(4)(2)、(3)如果没有手动调用赋值运算符重载函数
那么编译器也不会添加行为自动去调用赋值运算符重载函数
结果为该部分还是原值,所以必须手动调用
五、析构函数
1.编译器默认生成的析构函数
(1)对于内置类型的成员变量
不做任何处理
(2)对于自定义类型的成员变量
调用自定义类型的析构函数
(3)对于基类/父类
调用基类/父类的析构函数
2.显示定义的析构函数
(1)对于内置类型的成员变量
自己决定行为
(2)对于自定义类型的成员变量
调用自定义类型的析构函数
(3)对于基类/父类
调用基类/父类的析构函数
3.在析构函数中无论是否显示调用自定义类型、基类/父类的析构函数
都会在析构函数结束时调用一次自定义类型、基类/父类的析构函数
所以在析构函数中就不需要显示调用自定义类型、基类/父类的析构函数
不然会引发同一块内存空间二次析构
六、相互关系
1.构造函数是每一个类必写的,默认构造也是必写
2.如果一个类显示定义了析构函数,那么就需要显示写拷贝构造函数和赋值运算符重载函数
3.如果显示定义了构造函数,那么编译器还会生成拷贝构造函数
如果显示定义了拷贝构造函数,无论是否显示定义了构造函数
编译器都不再生成默认构造函数