==default和==delete
如果自行定义了一个构造/析构函数,那么编译器就不会再给一个默认的。如果强制加上=default,就可以重新获得并使用默认的。
=delete可以用在任意函数身上,用来通知编译器哪些函数是“删除”的,“删除”的函数不能以任何形式被使用,若调用则编译器会提示错误。
class Zoo {
public:
Zoo(int i1, int i2) :d1(i1), d2(i2) {}
Zoo(const Zoo&) = delete; //主程序不能再调用copy构造,否则会报错
Zoo(Zoo&&) = default; //主程序仍然使用编译器提供的默认的move构造,即使这里显式定义了
Zoo& operator=(const Zoo&) = default; //主程序仍然使用编译器提供的默认的copy赋值运算符,即使这里显式定义了
Zoo& operator=(const Zoo&&) = delete; //主程序不能再调用move赋值运算符,否则会报错
void func1() = default; //[Error]'void Zoo::func1' cannot be defaulted
void func2() = delete; //语法上OK, 不过一般都不会这样用
//~Zoo() = delete; //主程序不能再使用
~Zoo() = default; //使用默认的析构函数
private:
int d1, d2;
};
final和override说明符
动态绑定是通过同名虚函数的覆盖来实现的,对该实现有严格的语法要求,某些忽略可能会导致错误的行为。例如,派生类版本和基类版本的虚函数形参不一致,编译器会认为这二个版本的函数是相互独立的,这会导致派生类版本的函数没有覆盖掉基类的版本,也不会产生多态的行为。为了避免这类错误,C++11引入了override关键字以显式说明派生类的函数要覆盖基类的虚函数。类似地,可以使用关键字final阻止派生类覆盖基类版本的虚函数。
struct B {
virtual void f1(int) { }
virtual void f2() { }
void f3() { }
};
struct D1 : public B {
void f1() override { } //报错,基类没有不带参数的f1函数
void f2() final { } //D1::f2为最终版本,不可以再被override
void f3() override { } //报错,基类没有可覆盖的函数
}
struct D2 :public D1 {
void f2() { } //报错,不允许覆盖基类D1中的f2函数
};
关键字final除了作用于上面提到的虚函数外,还可以用来用来阻止类继承的发生。
class NoDerived final { }; //NoDerived不能作为基类
class Derived final: public Base1, public Base2 //被声明为final的类Derived不能再用作基类
{
}