20-默认的方法和禁用的方法
18.3.2 默认的方法和禁用的方法
C++11让您能够更好地控制要使用的方法。假定您要使用某个默认的函数,而这个函数由于某种原因不会自动创建。例如,您提供了移动构造函数,因此编译器不会自动创建默认的构造函数、复制构造函数和复制赋值构造函数。在这些情况下,您可使用关键字default显式地声明这些方法的默认版本:
class Someclass
{
public:
Someclass(Someclass &&);
Someclass() = default; // use compiler-generated default constructor
Someclass(const Someclass &) = default;
Someclass & operator=(const Someclass &) = default;
...
};
编译器将创建在您没有提供移动构造函数的情况下将自动提供的构造函数。
另一方面,关键字delete可用于禁止编译器使用特定方法。例如,要禁止复制对象,可禁用复制构造函数和复制赋值运算符:
class Someclass
{
public:
Someclass() = default; // use compiler-generated default constructor
// disable copy constructor and copy assignment operator:
Someclass(const Someclass &) = delete;
Someclass & operator=(const Someclass &) = delete;
// use compiler-generated move constructor and move assignment operator:
Someclass(Someclass &&) = default;
Someclass & operator=(Someclass &&) = default;
Someclass & operator+(const Someclass &) const;
...
};
第12章说过,要禁止复制,可将复制构造函数和赋值运算符放在类定义的private部分,但使用delete也能达到这个目的,且更不容易犯错、更容易理解。
如果在启用移动方法的同时禁用复制方法,结果将如何呢?前面说过,移动操作使用的右值引用只能关联到右值表达式,这意味着:
Someclass one;
Someclass two;
Someclass three(one); // not allowed, one an lvalue
Someclass four(one + two); // allowed, expression is an rvalue
关键字default只能用于6个特殊成员函数,但delete可用于任何成员函数。delete的一种可能用法是禁止特定的转换。例如,假设Someclass类有一个接受double参数的方法:
class Someclass
{
public:
...
void redo(double);
...
};
再假设有如下代码:
Someclass sc;
sc.redo(5);
int值5将被提升为5.0,进而执行方法redo()。
现在假设将Someclass类的定义改成了下面这样:
class Someclass
{
public:
...
void redo(double);
void redo(int) = delete;
...
};
在这种情况下,方法调用sc.redo(5)与原型redo(int) 匹配。编译器检测到这一点以及redo(int) 被禁用后,将这种调用视为编译错误。这说明了禁用函数的重要一点:它们只用于查找匹配函数,使用它们将导致编译错误。