Item11:Prefer delected functions to private undefined ones

Things to Remember:

  • 比起private和undefined,更好使用delected functions
  • 任何函数都可以被deleted,包括非成员函数和模板实例化

    如果你正在给其他的程序员提供code,但是你不想他们调用一些特定的函数,那么最简单的办法就是不要声明这些函数,没有声明就没有调用。但是有些时候,C++会为你声明一些函数,如果你想要阻止客户端调用这些函数就不太容易了。

 

C++98阻止使用function的方法是声明他们为priavte并且不定义他们。

例如iostream在C++标准库中的basic_ios。所有的istream和ostream class都继承自此类。复制istream和ostream是不被允许的,因为我们并不知道这样的操作应该做什么。一个istream对象,代表了一个输入值stream,一些值可能已经被读取了,一些值是潜在将会被读取的。如果一个istream被复制了,那么是否需要复制已经读过的所有值和将要读取的值?最简单的方式就是定义为不存在。禁止复制流就是这么做的。

使istream和ostream class不可复制,basic_ios在C++98中指定如下:

template<class charT,class traits = char_traits<char T>>
class basic_ios:public ios_base{
    public:
        ...
    private:
        basic_ios(const basic_ios&);//not define
        basic_ios& operator=(const basic_ios&); //not define  
};

 

    声明这些函数为private可以防止客户端调用他们。故意的不声明这些函数,当任然调用到他们之后(比如member function或者 friend of class),因为丢失函数定义,链接将会失效。

 

在C++11中 ,有更好的方式去实现相同的结果:“= delect”去标记复制构造函数和赋值操作符作为 delected functions。Delected function不能使用任何方法使用这个函数,即使是member和friend函数也是在尝试复制的时候编译失败。这是在C++98上的一种提升,C++98是当使用指导link-time的时候才会去诊断。

template<class charT,class traits = char_traits<char T>>
class basic_ios:public ios_base
{
    public:
        basic_ios(const basic_ios&) = delecte;
        basic_ios& operator=(const basic_ios&)=delect;
};

    一般来说,deleted functions被声明为public,而不是private。当客户端代码尝试去使用一个member 函数的时候,C++在删除状态之前检查可访问性。当客户端code尝试使用一个deleted private function,一些编译器只是会提示函数是私有的,尽管这个私有并不是真正的禁止访问的原因。所以将函数公开将会更好的看到编译器提示错误的消息。

一个重要的deleted function的好处就是任何!函数都可以是delected,但是C++98只有成员函数可以是private

如下面的例子,我们希望传入的参数值真正的int。但是C++继承的C意味着几乎所有的类型都可以被看做是模糊的数值,可以被隐式转换为int。实现这个的方法是要为过滤掉的类型实现deleted overloads。虽然不能使用这些deleted函数,但是它们还是code的一部分,因为在overload resolution的时候要考虑它们。这就是为什么下列函数在调用的时候会被拒绝。

 

bool isLucky(int number);
bool isLucky(char) = delete;//reject chars
bool isLucky(bool) = delete;
bool isLucky(double) = delete;//reject doubles and floats

 

另一个C++98不能实现而delected function可以实现的好处就是,禁止使用应该被禁止的模板实例化

在指针的世界中,有两种特殊的指针。一种是void*,因为没有办法解引用它,也没有办法增加或者删除它;另一种就是char*,因为它通常是指向C风格的string而不是单个字符的指针。这些情况是需要特殊处理的。我们假设当前例子是拒绝传入void*和char*这两种指针。

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

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

 

    如果你有一个template func在class内,你想要通过声明一些实例化通过声明private,我们不能这么做,因为在同一个类中,对于成员函数template跟主template有不同的level是不可能的!这里的问题是在于,模板特化(template specialization)必须是被写在namespace作用域中,而不是class作用域。对应已删除的函数不会出现这种问题,因为他们不需要不同的访问等级。他们可以在class外被deleted(在作用域内)。

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

template<>
void Widget::processPointer<void>(void*) = delete;//still public,but deleted

 

    坚定的选择使用deleted function!事实上,C++98声明private func,不真正的定义函数,真是C++11的deleted func实际上做的。但是C++98的方法不如C++11的好。C++98不能在class外部工作,在内部也不总是有用,当它产生用处的时候,就是可能已经在link-time了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值