news 2026/5/13 21:55:58

C++11新特性(十三)——默认函数控制=default与=delete

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++11新特性(十三)——默认函数控制=default与=delete

目录

1 类与默认函数

2 =default 和 =delete

2.1 =default

2.2 =delete


1 类与默认函数

在 C++ 中声明自定义的类,编译器都会默认自动生成一些程序员未自定义的成员函数,这些成员函数被称为默认函数特种成员函数

1.无参构造函数:创建类对象
2.
拷贝构造函数:拷贝类对象
3.
拷贝赋值函数:类对象赋值
4.
移动构造函数:拷贝类对象
5.
移动赋值函数:类对象赋值
6.
析构函数:销毁类对象

在C++语法规则中,一旦程序员实现了这些函数的自定义版本,则编译器不会再为该类自动生成默认版本。

2 =default 和 =delete

在 C++11 标准中称=default修饰的函数为显式默认函数,而称=delete修饰的函数为删除函数或者显示删除函数。C++11 引入显式默认函数和显式删除函数是为了增强对类默认函数的控制,让程序员能够更加精细地控制默认版本的函数。

2.1 =default

=default用于显式地告诉编译器为成员函数生成默认实现。这通常用于那些编译器默认不会自动生成的成员函数,比如自定义类型的拷贝构造函数和拷贝赋值运算符。

移动操作的生成条件仅当以下三者同时成立:

  • 该类未声明任何拷贝操作
  • 该类未声明任何移动操作
  • 该类未声明任何析构函数

在 C++11 及以后的版本,如果你想在已经存在任一拷贝操作或析构函数的条件下,仍然想让编译器自动生成移动操作,就需要通过 =default 来显示地表达这个想法

class MyClass { public: // 析构函数 ~MyClass() { std::cout << "Destructor called" << std::endl; } // 拷贝构造函数 MyClass(const MyClass& other) : data(other.data) { std::cout << "Copy constructor called" << std::endl; } // 拷贝赋值运算符 MyClass& operator=(const MyClass& other) { std::cout << "Copy assignment called" << std::endl; } // 显式声明移动构造函数 MyClass(MyClass&&) = default; // 显式声明移动赋值运算符 MyClass& operator=(MyClass&&) = default; // 默认构造函数 MyClass() = default; };

定义默认函数的注意事项:如果程序员对 C++ 类提供的默认函数(上面提到的六个函数)进行了实现,那么可以通过 =default 将他们再次指定为默认函数,不能使用 =default 修饰这六个函数以外的函数

class Base { public: Base() = default; Base(const Base& obj) = default; Base(Base&& obj) = default; Base& operator=(const Base& obj) = default; Base& operator=(Base&& obj) = default; ~Base() = default; // 以下写法全部都是错误的 Base(int a = 0) = default; //有参构造 Base(int a, int b) = default; //有参构造 void print() = default; //自定义函数 //不是移动、复制赋值运算符重载,不允许使用 =default 修饰 bool operator== (const Base& obj) = default; bool operator>=(const Base& obj) = default; };

2.2 =delete

在 C++98 中的 basic_ios 像下面这样规定的

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

通过将这些函数声明为private,就是为了阻止客户去调用它们。但某些情况下仍然可以访问(如成员函数或类的友元)并使用它们,这就会导致链接阶段缺少函数定义而报错。

在 C++11 中,有更好的途径来达成效果上相同的结果:使用=delete将拷贝构造和拷贝赋值将其标识为删除函数。以下是 C++11 中关于 basic_ios 的同一片段

template<class charT,class traits = char_traits<charT>> class basic_ios : publi ios_base { public: basic_ios(const basic_ios&) = delete; basic_ios& operator=(const basic_ios&) = delete; ... };

使用delete关键字和将函数声明为private看起来只是不同风格的选择,但实际上是有区别的。

1.使用 delete 删除的函数无法通过任何方法调用,即使是成员函数或友元函数中的代码也是无法调用的。相对于 private 的做法来讲,这是一种改进。

2.删除函数往往会被声明为 public。这样做的好处是,当客户代码尝试调用某个成员函数时,C++ 会先校验其可访问性,后校验删除状态。这么一来,当客户代码尝试调用某个 private 函数,编译器只会提示该函数为 private。所以把新的 delete 函数声明为 public 会得到更好的错误信息

3.任何函数都可以成为删除函数,但是只有类成员函数才能被声明为 private。举例来讲,如果我们有一个普通函数bool isLucky(int number),C++中很多类型可以隐式转换到 int ,所以会出现以下无意义的代码调用

if (isLucky('a')) //ok if (isLucky(true)) //ok if (isLucky(3.14)) //ok

当我们想要阻止这样的调用的时候,我们可以通过delete关键字来删除对应的重载版本

bool isLucky(int number); bool isLucky(char) = delete; //error bool isLucky(bool) = delete; //error bool isLucky(double) = delete; //error

4.删除函数还可以阻止那些不应该进行的模板实现。举例来讲,如果你需要一个和内建指针协作的模板

template <typename T> void processPointer(T* ptr) { // ... }

而指针的类型中有两个异类,一个是void*,因为无法对其进行自增、自减等操作;一个是char*,因为它们基本上表示的是 C 风格的字符串,而不是指向单个字符的指针。这时候我们可以通过删除函数来阻止对这两种类型的模板实现,而这一点是 private 无法做到的。

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;
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 23:28:54

如何高效配置Flutter CanvasKit渲染方案:5个关键优化策略

如何高效配置Flutter CanvasKit渲染方案&#xff1a;5个关键优化策略 【免费下载链接】engine The Flutter engine 项目地址: https://gitcode.com/gh_mirrors/eng/engine 还在为Flutter Web应用在复杂场景下的渲染卡顿和内存占用过高而困扰吗&#xff1f;作为基于WebAs…

作者头像 李华
网站建设 2026/5/11 22:39:00

光纤耦合装置的公差分析

摘要在现代光学中&#xff0c;光纤存在于各种光学系统中&#xff0c;能够将多少光耦合到光纤中一直是人们关注的问题。耦合效率对系统的对准十分敏感&#xff0c;特别是对于芯径相对较小的单模光纤。在本例中&#xff0c;我们选择了一个设计良好的光纤耦合透镜&#xff0c;并根…

作者头像 李华
网站建设 2026/4/30 21:48:13

Dify可视化AI应用开发平台的核心优势全面揭秘

Dify可视化AI应用开发平台的核心优势全面揭秘 在大模型技术席卷全球的今天&#xff0c;企业对AI落地的期待从未如此迫切。然而现实却常常令人沮丧&#xff1a;一个看似简单的智能客服系统&#xff0c;动辄需要数周甚至数月的开发周期&#xff1b;提示词稍作调整&#xff0c;整个…

作者头像 李华
网站建设 2026/5/11 21:22:23

3个结构化数据技巧,让你的GEO收录率飙升200%

在AI主导的信息获取时代&#xff0c;GEO&#xff08;生成引擎优化&#xff09;已成为企业内容战略的核心战场。据水滴互动2025年行业白皮书数据显示&#xff0c;采用结构化数据优化的企业&#xff0c;其内容被AI引擎引用的概率提升2.3倍&#xff0c;决策链路转化率提高47%。本文…

作者头像 李华
网站建设 2026/5/6 17:10:45

Linux实时调度:3大策略对比与实战配置指南 [特殊字符]

Linux实时调度&#xff1a;3大策略对比与实战配置指南 &#x1f680; 【免费下载链接】linux-insides-zh Linux 内核揭秘 项目地址: https://gitcode.com/gh_mirrors/li/linux-insides-zh 还在为系统响应延迟而烦恼&#xff1f;Linux内核的实时调度机制正是你需要的解决…

作者头像 李华