• 优先选用删除函数,而不是private未定义函数
  • 任何函数都可以删除,包括非成员函数和模板具现

  我们时常会面临这种情况,程序中我们有一些不希望外部调用的函数。虽然我们可以不声明不定义,但是对于一些自动生成的函数,比如复制构造函数和复制赋值运算符,这些函数在某些情况下也不希望外部调用。

  一个例子,C++标准库中输入输出流库继承谱系基类部位的,是类模板basic_ios,所有的输入输出流都继承该类。对于输入输出流进行复制是不可取的,因为我们不知道要落实成什么样子。对于一个istream对象表示一个输入流值,其中只有一部分被读取了,要对这个对象进行复制,我们不清楚到底要不要复制那部分还未读取的值。所以不允许外部调用复制运算符。

  这种禁止外部调用C++自动生成的函数的方法,在C++98中的做法是把函数声明为私有的,并且不去定义它。将这些函数声明为private,就阻止了外部去调用。故意不去定义它们,就意味著如果内部成员或类的友元要调用,链接阶段就会由于缺少函数定义而失败。

//C++98中的basic_ios中的规定
template<class charT,class traits = char_traits<charT>>
class basic_ios : public ios_base{
public:
...
private:
	basic_ios(const basic_ios&);		//not defined
	basic_ios& operator=(const basic_ios&); //not defined
};

  C++11中有更好的途径来达成相同的效果:使用“=delete”将复制构造函数和复制赋值运算符标识为删除函数

//C++11中的basic_ios中的规定
template<class charT,class traits = char_traits<charT>>
class basic_ios:public ios_base{
public:
	basic_ios(const basic_ios&) = delete;
	basic_ios& operator=(const basic_ios&) = delete;
};
  • 删除函数无法通过任何方式使用,即使成员函数和友元函数中的代码试图复制删除函数也会无法工作。而C++98中这种情况到链接阶段才能诊断出来。
  • 删除函数要设置成public属性。这样当客户代码尝试使用某个成员函数时,C++会先校验可访问性,后校验删除状态。如果定义成为private,当客户代码想要调用删除函数,编译器只会提示该函数为private,而不是提示这是删除函数。
  • 任何函数都能成为删除函数,但只有成员函数才能够声明为private属性。
    比如说有个非成员函数,取用一个整数,并返回其是否是个幸运数。C++由于来自于C,所以对于那些可以凑活看成是数值的型别都可以隐式转化为int,但是这样对于有些调用就失去了意义
bool isLucky(int number);

if(isLucky(30))		//正常调用

if(isLucky('a'))	//能调用,但是无意义

if(isLucky(true))	//能调用,无意义

if(isLucky(3.5))	//不知道是否要截断

为了阻止这些无意义的函数通过编译,可以为我们想要滤掉的型别创建删除重载版本。虽然删除函数不可被使用,但它还是程序的一部分。因此在重载决议时还是被纳入考量。所以那些无意义的调用都会被拒绝编译:

bool isLucky(int number);	//原始版本
bool isLucky(char) = delete; //拒绝char型别
bool isLucky(bool) = delete;	//拒绝bool型别
bool isLucky(double) = delete;  //拒绝double和float型别
//最后一个函数之所以能够同时拒绝double和float,是因为float型别在面对临时转型
//到int还是double时,优先转型到double
  • 删除函数还能够阻止不应该进行的模板具现。这在C++98中是做不到的,把这些模板写成私有的是无法通过编译的。例如一个我们要一个和内建指针协作的模板,而指针中有两个异类:一个是void*,它无法对其执行提领、自增、自减等操作;还有一个是char*指针,因为它基本表示的是C风格字符串而不是指涉到单个字符的指针。所以我们要屏蔽掉它们。
template<>
void processPointer<void>(void*) = delete;
void processPointer<char>(char*) = delete;
void processPointer<const void>(const void*) = delete;
void processPointer<const char>(const char*) = delete;