虚析构函数
由于继承会发生静态类型与动态类型不一致的情况,所以使用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将使编译器产生代码,形成派生类可以使用的构造函数
基类构造函数的默认实参不会被继承,派生类的构造函数将获得多个继承的构造函数,每个构造函数分别省略掉一个含有默认实参的形参
如果派生类可以定义一部分具有相同参数列表的构造函数,就将不会继承这些,同时默认的构造不会被继承,还是由编译器来合成