如果你写了代码给其他开发人员使用,并且你想阻止他们调用某个特定函数的话,那你只需要不要声明该函数即可。函数未经声明,不可调用。但是有时C++
会替你声明函数;
C++98
中为了阻止这些函数被使用采取的做法是声明其为private
,并且不去定义它们;举例来说,在接近C++
标准的输入输出流库继承谱系基类部位的,是类模板basic_ios
,对输入输出流进行复制是不可取的;在C++98
中的basic_ios
是像下面这样规定的:
template<class charT, char tarits = char_tarits<char T>>
class basic_ios : public ios_base {
public:
//...
private:
basic_iso(const basic_ios&); // not defined
basic_iso& operator=(const basic_ios&); // not defined
};
通过将这些函数声明为private
,就阻止了客户去调用它们。而故意不去定义它们,就意味着如果一段代码仍然可以访问他们(如成员函数,或类的友元)并使用了它们,链接阶段就会由于缺少函数定义而告失败;
在C++11
中,有更好的途径:使用=delete
将复制构造函数和复制赋值运算符标识为删除函数.
template<class charT, char tarits = char_tarits<char T>>
class basic_ios : public ios_base {
public:
basic_iso(const basic_ios&) = delete;
basic_iso& operator=(const basic_ios&)= delete;
};
删除函数无法通过任何方法使用,所以即使成员函数和友元函数中的代码也会因试图复制basic_iso
类型对象而无法工作。
删除函数会被声明为public
,而非private
,好处是因为当客户代码尝试使用某个成员函数时,C++
会先校验可访问性,后校验删除状态。这样一来,当客户代码试图调用某个private
删除函数时,有些编译器只会抱怨改函数为private
;
删除函数一个重要优点为:任何函数都可以成为删除函数,但是只有成员函数才能声明为priavate
;假如有个非成员函数:
bool isLucky(int number);
if (isLicky('a')) ... // 'a'是幸运数么
if (isLicky(true)) ... // 'true'又如何?
if (isLicky(3.5)) ... // 是否截断为3再传参数
如果我们想禁止以上类型转换调用,有个办法就是将我们想要滤掉类型i定义为delete
bool isLucky(int number);
bool isLucky(char); // 拒绝char类型
bool isLucky(bool); // 拒绝bool类型
bool isLucky(double); // 拒绝double和float类型
还有一个作用就是阻止那些不应该进行的模板实现,比如,你需要一个内建指针协作的模板:
template<typename T>
void processPointer(T *ptr);
指针世界有两个异类,一个是void *
指针,无法进行自增,自减等操作;一个是char *
指针,本质上代表是C
风格的字符串,而不是指涉到单个字符的指针。我们假定这样的特殊处理手法就是在采用这两个类型时拒绝调用:
template<>
void processPointer<void>(void *) = delete;
template<>
void processPointer<char>(char *) = delete;
如果是类内部的函数模板,并且你想通过private
声明来禁用某些实现,这是做不到的,因为你不可能给予成员函数模板的讴歌特化以不同于主模板的访问层级:
class Widget {
public:
template<typename T>
void processPointer(T *ptr){}
private:
template<> //错误!!!
void processsPointer<void>(void *);
};