Effective Modern C++ Item 11 优先选用删除函数,而非private未定义函数

有时候,你写了代码给其他程序员用,并且你想组织他们调用某个特定函数的话,你只需不要声明该函数即可。函数未经声明,不可调用,易如反掌。但是有些特定函数编译器会帮你生成,那么这个时候C++98里的一种常用处理方式是将其声明为私有函数,并且不去定义他们。例如如下代码:

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中,有更好的途径达到上述效果:

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++11中这样简单的改动,其实彻底断绝了这些被禁止的函数的调用。声明私有不定义的方式,在编译阶段友元函数一样可以调用他们,在链接阶段才会因为未定义报错,而C++11中连编译阶段都无法进行下去。

习惯上,把delete函数定为public

编译器一般会先校验可访问性,然后校验删除状态。如果设置为private则编译器报错的时候,不会告知其为删除函数,而报告private属性。在修改遗留代码的时候切记将private换为public

优势1:任何函数均可设置为delete,但只有成员函数可以private

看一个例子:

bool isLucky(int number);

if (isLucky('a')) ...   //'a'是个幸运数字么
if (isLucky(true)) ...  //true又如何
if (isLucky(3.5)) ...  //是不是应该先截断为3,再检查是否幸运

如果幸运数字必须是整数,那么我们想要阻止上面这样的调用通过编译,而delete这个时候有个这样的用法:

bool isLucky(int number);      //原始版本
bool isLucky(char);            //拒绝char型别
bool isLucky(bool);            //拒绝bool型别
bool isLucky(double);          //拒绝double和float型别

以上有个特殊点在于,删除了double但是float也禁止了。因为float面临转入int还是double的时候,会使用double型别。然后发现double型别函数被删除了,所以也被禁止了。所以这里禁止函数的机制,是

尽管删除函数不可使用,但它们还是程序的一部分,在重载的时候还是会被纳入考量,如果发现被删除,则拒绝编译。

优势2:阻止不应该具现的模板

例子:

template<typename T>
void processPointer(T* ptr);

如果这个函数的业务是,对指针对象进行处理。那么这个函数需要排除两类指针以防错误,void*类型指针和char*类型指针。他们一个无法指到具体对象,一个一般用来指向C风格的字符串。那么这两类传入应该拒绝具象化。

template<>
void processPointer<void>(void *) = delete;
template<>
void processPointer<char>(char *) = delete;

那么其实对应的const版本应该也是不行的,于是有:

template<>
void processPointer<const void>(const void *) = delete;
template<>
void processPointer<const char>(const char *) = delete;

如果想要斩草除根,那么对应的const volatile, std::wchar_t, std::char16_t, std::char32_t也都应该删除。

而有意思的是,

如果是类内部的函数模板,prviate声明禁止某些具象化是办不到的。

例如如下错误示例:

class Widget {
public:
...
    tempalte<typename T>
    void processPointer(T* ptr);
   {...}
private: 
    template<>                 //错误!
    void processPointer<void>(void *);
};

问题在于,模板特化是必须在名字空间作用域而非类作用域内撰写的。这个问题在删除函数上不会体现出来,因为:

  • 他们根本不需要不同的访问层级

  • 成员函数模板可以在类外被删除,如下:

class Widget {
public:
...
    tempalte<typename T>
    void processPointer(T* ptr);
   {...}
   ...
};

template<>         //仍然具备public访问层级但被删除了
void processPointer<void>(void *) = delete;

实际上,C++98的private手法想实现的效果就是delete函数的效果,所以请记住。始终使用删除函数

要点速记
1. 优先选用删除函数,而非private未定义函数。
2. 任何函数都可以删除,包括非成员函数和模板具现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值