条款11:优先选用删除函数,而非private未定义函数

1 删除函数

  1. 在C++ 11之前,如果想禁止某成员函数(几乎总是拷贝构造函数或赋值运算符)的使用,可以将其声明为private,并且不提供定义。
    例如,istreams和ostream对象不该被拷贝,因为并不清楚应该做什么。
cpp 复制代码
template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
...
private:
    basic_ios(const basic_ios& ); 		// 不定义,如果使用会在链接时出错
    basic_ios& operator=(const basic_ios&); 	// 不定义
};
  1. 在 C++11 中,有一种更好的方法:使用"= delete"将拷贝构造函数和拷贝赋值运算符标记为已删除的函数。
cpp 复制代码
template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
    ...
    //已删除的函数不能以任何方式使用,即使是成员函数和友元函数也是如此,如果试图拷贝 basic_ios 对象,也将无法编译通过
    basic_ios(const basic_ios& ) = delete;
    basic_ios& operator=(const basic_ios&) = delete;
    ...
    //C++ 在检查已删除状态之前会检查可访问性。如果放在private之下,可能得到的错误提示只是没有访问权限
};
  1. 已删除函数的一个重要优势是任何函数都可以被删除,而只有成员函数可以是私有的。
cpp 复制代码
bool isLucky(int number); //非成员函数
if (isLucky('a')) ...     // 'a' 是幸运数字吗?
if (isLucky(true)) ...    // "true"呢?
if (isLucky(3.5)) ...     // 我们应该将其截断为3,再进行判断吗?

如果幸运数字必须是整数,需要防止这样的调用。可以创建已删除的重载来进行过滤:

cpp 复制代码
bool isLucky(int number);       // 原始的函数 
bool isLucky(char) = delete;    // 拒绝 char
bool isLucky(bool) = delete;    // 拒绝 bool
bool isLucky(double) = delete;  // 拒绝 double 和 float

虽然已删除的函数不能被使用,但它们仍然是程序的一部分。因此会参与重载解析。

cpp 复制代码
if (isLucky('a')) ...     // 错误! 调用已删除函数
if (isLucky(true)) ...    // 错误!
if (isLucky(3.5f)) ...    // 错误!
  1. 已删除函数可以(而私有成员函数则不能)防止使用应该禁用的模板实例化。
cpp 复制代码
template<typename T>
void processPointer(T* ptr);
template<>
void processPointer<void>(void*) = delete;
template<>
void processPointer<char>(char*) = delete;
template<>
void processPointer<const void>(const void*) = delete;
template<>
void processPointer<const char>(const char*) = delete;
  1. 无法为成员函数模板特化提供与主模板不同的访问级别。如果processPointer是Widget内部的成员函数模板:
cpp 复制代码
class Widget {
public:
    ...
    template<typename T>
    void processPointer(T* ptr)
    { ... }
private:
    template<> // 错误!
    void processPointer<void>(void*);
};

问题在于模板特化必须在命名空间范围内编写,而不是类范围内。已删除的函数不需要不同的访问级别,可以在类外删除(在命名空间范围内):

cpp 复制代码
class Widget {
public:
    ...
    template<typename T>
    void processPointer(T* ptr)
    { ... }
    ...
};

template<> 
void Widget::processPointer<void>(void*) = delete;

2 要点速记

  1. 优先选择已删除函数而不是私有未定义的函数。
  2. 任何函数都可以被删除,包括非成员函数和模板实例化。
相关推荐
2601_966949657 小时前
为什么量化策略需要大量历史股票数据?从回测可信度理解数据规模
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
niucloud-admin7 小时前
JAVA V6 多商户商城 开发文档——插件目录结构
java·开发语言
anew___7 小时前
蜂鸣器播放音乐——让 Arduino 唱出旋律
c++·stm32·单片机·嵌入式硬件·c
滕州市燕猫虎计算机科技工作室个体工商户7 小时前
Java锁
java·开发语言
多加点辣也没关系8 小时前
JavaScript|第31章:表单与控件
开发语言·javascript·ecmascript
菜鸟~noob2338 小时前
【电子战】 第09篇:阵列信号处理——波束形成、MVDR、MUSIC【含matlab代码】
开发语言·matlab·信号处理
ocean21038 小时前
2025-2026年Python面试高频知识点洞察
开发语言·python·面试·python八股文
零依赖极客8 小时前
Day 6·1 ARMv8.2 dotprod——vdotq_s32 一条指令做 4 个点积
c语言·开发语言·人工智能·矩阵·arm·vllm
stolentime8 小时前
洛谷P10515 转圈题解
c++·算法·数学建模·贪心算法
tdtsmt9 小时前
穿戴硬件量产工艺实录:天地通电子智能手表主板 SMT 贴片案
c++