虚析构函数
由于继承会发生静态类型与动态类型不一致的情况,所以使用delete时,可能造成错误,此时使用虚析构函数可以比较方便的解决,虚析构函数将自主的确定该使用哪种类的析构函数进行内存销毁
如果类定义了析构函数,即使使用default的合成版本,编译器也不会再合成移动操作

删除的拷贝控制基类的关系
(1)基类的操作变成被删除或者不可访问,派生类操作成为被删除,因为派生类的基类部分无法进行构造
(2)基类的析构删除或不可访问,派生类默认和拷贝构造删除,因为编译器无法销毁基类
(3)基类析构或移动是删除的,派生类的移动也删除,因为基类部分无法移动

class B
{
public:
    B();
    B(const B&) = delete;//定义了删除的拷贝构造,因为有自己定义的拷贝构造,编译器不会合成移动构造
};
class D : public B
{
};
D d;//正确,默认构造
D d2(d);//错误,无拷贝构造
D d3(std::move(d));//错误,无移动构造

移动操作与继承
如果需要移动操作,就要从基类开始定义,并且要拷贝、移动都定义

派生类的拷贝控制成员
派生类在拷贝和移动自己的成员的同时,还需要拷贝和移动基类部分的成员

定义派生类拷贝和移动构造函数

class Base{...};
class D : public Base
{
public:
    D(const D& d) : Base(d)
    {D成员的初始值}//利用委托,把D类型的d对象传给基类的构造函数,绑定到基类构造函数中需要Base&形参的构造函数上,从而拷贝基类部分的成员,D部分成员由自己完成,如果不使用委托,派生类的基类部分将被默认初始化
    D(D&& d) : Base(std::move(d))
    {D成员的初始值}
};

派生类赋值运算符

D &D::operator=(const D &rhs)
{
    Base::operator=(rhs);//显式的帮助派生类成员赋值
    return *this;
}

派生类析构函数
派生类会先析构,并且只会析构派生类自己分配的资源

继承的构造函数
派生类继承基类构造函数的方式是提供一条注明了直接基类名的using声明语句

class D : public B
{
public:
    using B::B;//继承B的构造函数
    double net_price(std::size_t) const;
};

通常情况下using的作用是使某个名字在当前作用域内可见,但当作用于构造函数时,using将使编译器产生代码,形成派生类可以使用的构造函数
基类构造函数的默认实参不会被继承,派生类的构造函数将获得多个继承的构造函数,每个构造函数分别省略掉一个含有默认实参的形参
如果派生类可以定义一部分具有相同参数列表的构造函数,就将不会继承这些,同时默认的构造不会被继承,还是由编译器来合成