BIG 5 :拷贝构造/赋值函数,移动构造/赋值函数,析构函数之间的关系(包括从父类继承时的情况)
默认构造函数
- 当除了析构函数外没有其他任何默认函数,会自动生成默认构造函数,否则构造函数无法自动生成(即存在除析构函数意以外的任何其他BIG5之一),必须显示声明默认构造函数,即使他什么也不做。
- 即使显示声明的默认构造函数什么也不做,编译器也将其认为是复杂的,其不如自动生成的默认构造函数来的高效,并且也不会被认为是 POD 类型。
默认拷贝构造/赋值函数
1.C++11 标准还规定了如下规则:
- 如果拷贝构造函数或者析构函数被显示声明,那么拷贝赋值运算符就不会自动生成
- 如果拷贝赋值运算符或者析构函数被显示声明,那么拷贝构造函数就不会自动生成
- 这两种情况下, Visual Studio 仍然会自动生成必要的函数,并不会产生告警。
2.当显示定义了任意移动构造/移动赋值函数时(包括通过default指定的),编译器不会再自动合成拷贝构造/拷贝赋值函数(即使是default指定的移动构造/移动赋值函数也被认为是显示定义的)
默认移动构造/移动赋值函数
1.只有在没有显示定义任何BIG 5(注意:包括析构函数)之一时,编译器才会自动合成。
使用default指定的默认函数(注意default只能指定默认无参无初始化列表的构造函数和BIG5,其他不适用),与自动合成的默认函数的相同与不同:
1.相同:在调用父类相应函数时,与自动合成的默认函数表现出一致特性(功能性)
2.不同:即使是default指定的,也被认为是人工显示定义的(存在性)
单继承
核心:在构造子类之前一定要执行父类的一个构造函数。
1.构造函数(不包括复制构造函数)。
顺序:①直接父类;②自己
注意:若直接父类还有父类,那么“直接父类的父类”会在“直接父类” 之前 构造。 可以理解为这是一个递归的过程,知道出现一个没有父类的类才停止。
2.1 如果没有显式定义构造函数,则“合成的默认构造函数”会自动调用直接父类的“默认构造函数”,然后调用编译器为自己自动生成的“合成的默认构造函数”。
2.2 如果显式定义了自己的构造函数
2.2.1 如果没有显式调用直接父类的任意一个构造函数,那么和“合成的默认构造函数”一样,会先自动调用直接父类的 默认构造函数,然后调用自己的构造函数。
2.2.2 如果显式调用了直接父类的任意一个构造函数,那么会先调用直接父类相应的构造函数,然后调用自己的构造函数。
2. 拷贝构造函数
顺序:①直接父类;②自己
注意:和构造函数一样,若直接父类还有父类,那么“直接父类的父类”会在“直接父类” 之前 构造。 可以理解为这是一个递归的过程,知道出现一个没有父类的类才停止。
2.1 如果 “没有显式定义拷贝构造函数” 或者 “使用default显式定义拷贝构造函数”时,则“合成的拷贝构造函数”会自动调用直接父类的“拷贝构造函数”,然后调用编译器为自己自动生成的“合成的拷贝构造函数”(注意:不是默认构造函数)
注意:当有任何显示定义的移动类函数时,编译器会删除所有默认的拷贝类函数
2.2 如果显式定义了自己的拷贝构造函数 (和构造函数类似)
2.2.1 如果没有显式调用父类的任意一个构造函数,那么会先调用直接父类的 默认构造函数(注意:不是 拷贝构造函数)。
2.2.2 如果显式调用了直接父类的任意一个构造函数,那么会先调用直接父类相应的构造函数。
3.拷贝赋值函数
3.1 如果 “没有显式定义拷贝赋值函数” 或者 “使用default显式定义拷贝赋值函数”时,会自动调用直接父类的拷贝赋值函数。(注意:不是 默认构造函数)
注意:当有任何显示定义的移动类函数时,编译器会删除所有默认的拷贝类函数
3.2 如果显式定义了,就只执行自己定义的版本,不再自动调用直接父类的任何函数,只执行自己的拷贝赋值函数。
注意:如有需要对父类子部分进行赋值,应该在自己编写的代码中,显式调用父类的赋值操作符。
4.移动构造函数
与2.拷贝构造函数情况类似,注意:只有当没有任何显示定义的BIG5之一时(即使是default指定的big5也被认为是显示定义的),才会自动合成
5.移动赋值函数
与3. 拷贝赋值函数情况类似,注意:只有当没有任何显示定义的BIG5之一时(即使是default指定的big5也被认为是显示定义的),才会自动合成
6. 析构函数
与构造函数 顺序相反。
参考:https://www.cnblogs.com/wanmeishenghuo/p/9610272.html