选用删除函数,而不是使用private未定义的函数

c++98中通常就函数定义为private,来表示这个函数不可用。比如常见的禁止复制构造函数或者复制拷贝函数。当然private也有些好的用法,比如单例中。
但是我们这里讨论的是删除某个函数。

class NonCopyable {
 protected:
  NonCopyable() = default;
  ~NonCopyable() = default;

 private:
  NonCopyable(const NonCopyable& ) = delete;
  NonCopyable(NonCopyable&& ) = delete;
  NonCopyable& operator=(const NonCopyable& ) = delete;
  NonCopyable& operator=(NonCopyable&& ) = delete;
};

用delete来表示删除这个函数。

1. 为什么要这么做呢?

因为如果我们定义为private的时候,可能这个类的成员函数或者类的友元还是可以使用private定义的。

如果我们希望代码中不要每次都把相应复制构造函数或者复制拷贝函数都删掉,可以继承上述写的类

class A : public NoCopyable {
  // ....
};

当然还可以在NoCopyable中添加你想要删除的函数。

当然上述代码中也存在一个问题,就是删除函数最好是声明为public

2. 为什么删除函数最好声明为public?

因为当客户端代码尝试访问一个声明为private的删除的函数时,编译器会优先校验可访问性,然后判断是否删除。
所以会这时候可能得到错误的报错信息。

3. 任何函数都可已删除

不仅时成员函数,还包括非成员函数和模板具现。
比如一个非成员函数

bool isLucky(int number); // 这里我们接受一个int的,判断他是否是幸运数字。

我们发现我们输入int, float, double, bool都可以,因为这里存在隐式转换。
但是如果我们就想只接受一个int的呢,那么我们就将不要的删除就好了。

bool isLucky(bool) = delete;
bool isLucky(char) = delete;
bool isLucky(double) = delete;
注意删除double,同时就删除了float

因为当我们输入一个float的变量时,将面临一个隐式转换。而转换规则可以从float转成int和double时,优先选用double.
而此时发现double的已经被删除了,那么编译就会被阻止。

还有就是当这个时一个类内部的函数模板时,会遇到新的问题。

class Widget {
 public:
  tempalte <typename T>
  void Process(T* ptr) {
  }
private:
 template<>
 void Process(void*);  // 编译不通过,这里我们想做一个让传入void*类型的参数的函数调用不能通过
};

因为 模板的特化必须在名字作用域而非类的作用域撰写的。
所以我们改成这样

class Widget {
 public:
  tempalte <typename T>
  void Process(T* ptr) {
  }
};
template<>
void Widget::Process<void>(void*) = delete;
posted @ 2021-01-11 19:43  cyssmile  阅读(140)  评论(0编辑  收藏  举报