类的拷贝控制操作:
- 拷贝构造函数
- 拷贝赋值运算符
- 移动构造函数
- 移动赋值运算符
- 析构函数
拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么。
拷贝和移动运算符定义了将一个对象赋予另一个对象时做什么。
析构函数定义了当此类型的对象销毁时做什么。
拷贝构造函数的定义
如果一个构造函数的第一个参数是自身类类型的引用,且没有其他参数或其他参数都有默认值,则此构造函数为拷贝构造函数。
struct Example {
Example(); //构造函数
Example(const Example &); //拷贝构造函数
};
何时会发生拷贝初始化
- 将一个对象作为实参传递给一个非引用类型的形参
- 从一个返回类型为非引用类型的函数返回一个对象
- 用花括号列表初始化一个数组中的元素或一个聚合类中的成员
- 用 = 定义变量时。
为何拷贝构造函数的第一个参数必须为引用
因为拷贝构造函数被用来初始化非引用类类型的参数。
析构函数完成哪些工作
在一个析构函数中,首先执行函数体,然后销毁成员。成员按初始化顺序的逆序销毁。
成员销毁时的动作完全依赖与成员类型。销毁类类型成员需要执行其析构函数。内置类型没有析构函数,因此销毁内置类型成员什么也不需要做。
何时会调用析构函数
只要一个对象被销毁,就会自动调用其析构函数:
- 变量在离开其作用域时被销毁
- 当一个对象被销毁时,其成员被销毁
- 容器被销毁时,其元素被销毁
- 对于临时对象,当创建它的完整表达式结束时被销毁。
- 对于动态分配的对象,当对指向它的指针执行 delete运算符时被销毁。
如何阻止类对象的拷贝
C++11及更高版本,允许定义删除的函数。可以通过将拷贝构造函数和拷贝复制运算符定义为删除的函数来阻止拷贝。删除的函数是这样一种函数:虽然声明了该函数,但不能以任何方式使用它。
struct NoCopy {
NoCopy() = default;
NoCopy(const NoCopy &) = delete; //阻止拷贝
NoCopy& operator= (const NoCopy &) = delete; //阻止赋值
~NoCopy() = default;
};
如果把析构函数定义成删除的会发生什么
如果一个类的析构函数是删除的,编译器将不允许定义该类的对象或创建临时变量。
如果一个类的成员的类型删除了析构函数,编译器也不允许定义该类的对象或创建临时变量。
但是可以动态分配这种类型的对象,且不能通过delete释放。
struct NoDtor {
NoDtor() = default;
~NoDtor() = delete;
};
NoDtor nd; //不允许
NoDtor *p = new NoDtor(); //允许
delete p; //不允许
std::move 的作用
获得绑定到左值上的右值引用。当对一个对象调用 std::move 后,就意味着除了对其赋值和销毁外,我们将不再使用它。
多重继承的派生类的初始化
- 派生类的构造函数只能初始化它的直接基类。
- 基类的构造顺序与派生列表中基类的顺序一直,而与派生类构造函数的初始值列表中基类的顺序无关。
多重继承下的类作用域
在只有一个基类的情况下,派生类的作用域嵌套在直接基类和简洁基类的作用域中。查找过程沿着继承体系自底向上进行,直到找到所需的名字。派生类的名字将隐藏基类的同名成员。
在多重继承的情况下,相同的查找过程在所有直接基类中同时查找。如果名字在多个基类中被找到,则对该名字的使用具有二义性。此时需要指定具体是要使用哪一个成员。
#include <bits/stdc++.h>
using namespace std;
struct BaseA {
int value;
};
struct BaseB {
int value;
};
struct D : BaseA, BaseB {
int data;
};
int main() {
D d;
d.value = 10; // request for member ‘value’ is ambiguous
d.BaseB::value = 10; //ok
return 0;
}
菱形继承
派生类可以通过它的两个直接基类分别继承自同一个间接基类,也可以直接继承某个基类,然后通过另一个基类再一次间接的继承该类。
如果避免菱形继承
虚继承的目的是令某个类做出声明,承诺愿意共享它的基类。其中,共享的基类子对象称为虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含唯一一个共享的虚基类子对象。
虚继承对象的构造方式
含有虚基类的对象的构造函数与一般的顺序稍有区别:首先使用提供给最底层派生类构造函数的初始值初始化该对象的虚基类子部分,接下来按照直接基类在派生类列表中出现的次序依次对其进行初始化。即使虚基类并不是派生类的直接基类,也可在派生类的构造函数初始化列表中调用虚基类的构造函数。
如果感觉有点意思,可以关注👏HelloNebula👏
- 分享周赛题解
- 分享计算机专业课知识
- 分享C++相关岗位面试题
- 分享专业书籍PDF