• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 详解在C++中显式默认设置的函数和已删除的函数的方法

详解在C++中显式默认设置的函数和已删除的函数的方法

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++ 虚函数详解,c++指针详解,c++编程实例详解,c++关键字详解,c++编程实例详解pdf等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

在 C++11 中,默认函数和已删除函数使你可以显式控制是否自动生成特殊成员函数。已删除的函数还可为您提供简单语言,以防止所有类型的函数(特殊成员函数和普通成员函数以及非成员函数)的参数中出现有问题的类型提升,这会导致意外的函数调用。
显式默认设置的函数和已删除函数的好处
在 C++ 中,如果某个类型未声明它本身,则编译器将自动为该类型生成默认构造函数、复制构造函数、复制赋值运算符和析构函数。这些函数称为特殊成员函数,它们使 C++ 中的简单用户定义类型的行为如同 C 中的结构。也就是说,可以创建、复制和销毁它们而无需任何额外编码工作。C++11 会将移动语义引入语言中,并将移动构造函数和移动赋值运算符添加到编译器可自动生成的特殊成员函数的列表中。
这对于简单类型非常方便,但是复杂类型通常自己定义一个或多个特殊成员函数,这可以阻止自动生成其他特殊成员函数。实践操作:

  • 如果显式声明了任何构造函数,则不会自动生成默认构造函数。
  • 如果显式声明了虚拟析构函数,则不会自动生成默认析构函数。
  • 如果显式声明了移动构造函数或移动赋值运算符,则:
  1. 不自动生成复制构造函数。
  2. 不自动生成复制赋值运算符。
  • 如果显式声明了复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符或析构函数,则:
  1. 不自动生成移动构造函数。
  2. 不自动生成移动赋值运算符。

注意

此外,C++11 标准指定将以下附加规则:

  • 如果显式声明了复制构造函数或析构函数,则弃用复制赋值运算符的自动生成。
  • 如果显式声明了复制赋值运算符或析构函数,则弃用复制构造函数的自动生成。
  • 在这两种情况下,Visual Studio 将继续隐式自动生成所需的函数且不发出警告。

这些规则的结果也可能泄漏到对象层次结构中。例如,如果基类因某种原因无法拥有可从派生类调用的默认构造函数 - 也就是说,一个不采用任何参数的 public 或 protected 构造函数 - 那么从基类派生的类将无法自动生成它自己的默认构造函数。

这些规则可能会使本应直接的内容、用户定义类型和常见 C++ 惯例的实现变得复杂 — 例如,通过以私有方式复制构造函数和复制赋值运算符,而不定义它们,使用户定义类型不可复制。

struct noncopyable
{
 noncopyable() {};

private:
 noncopyable(const noncopyable&);
 noncopyable& operator=(const noncopyable&);
};

</div>

在 C++11 之前,此代码段是不可复制的类型的惯例形式。但是,它具有几个问题:
复制构造函数必须以私有方式进行声明以隐藏它,但因为它进行了完全声明,所以会阻止自动生成默认构造函数。如果你需要默认构造函数,则必须显式定义一个(即使它不执行任何操作)。
即使显式定义的默认构造函数不执行任何操作,编译器也会将它视为重要内容。其效率低于自动生成的默认构造函数,并且会阻止 noncopyable 成为真正的 POD 类型。
尽管复制构造函数和复制赋值运算符在外部代码中是隐藏的,但成员函数和 noncopyable 的友元仍可以看见并调用它们。如果它们进行了声明但是未定义,则调用它们会导致链接器错误。
虽然这是广为接受的惯例,但是除非你了解用于自动生成特殊成员函数的所有规则,否则意图不明确。
在 C++11 中,不可复制的习语可通过更直接的方法实现。

struct noncopyable
{
 noncopyable() =default;
 noncopyable(const noncopyable&) =delete;
 noncopyable& operator=(const noncopyable&) =delete;
};
</div>

请注意如何解决与 C++11 之前的惯例有关的问题:
仍可通过声明复制构造函数来阻止生成默认构造函数,但可通过将其显式设置为默认值进行恢复。
显式设置的默认特殊成员函数仍被视为不重要的,因此性能不会下降,并且不会阻止 noncopyable 成为真正的 POD 类型。
复制构造函数和复制赋值运算符是公共的,但是已删除。定义或调用已删除函数是编译时错误。
对于了解 =default 和 =delete 的人来说,意图是非常清楚的。你不必了解用于自动生成特殊成员函数的规则。
对于创建不可移动、只能动态分配或无法动态分配的用户定义类型,存在类似惯例。所有这些惯例都具有 C++11 之前的实现,这些实现会遭受类似问题,并且可在 C++11 中通过按照默认和已删除特殊成员函数实现它们,以类似方式进行解决。
显式默认设置的函数
可以默认设置任何特殊成员函数 — 以显式声明特殊成员函数使用默认实现、定义具有非公共访问限定符的特殊成员函数或恢复其他情况下被阻止其自动生成的特殊成员函数。
可通过如此示例所示进行声明来默认设置特殊成员函数:

struct widget
{
 widget()=default;

 inline widget& operator=(const widget&);
};


inline widget& widget::operator=(const widget&) =default;

</div>

请注意,只要特殊成员函数可内联,便可以在类主体外部默认设置它。
由于普通特殊成员函数的性能优势,因此我们建议你在需要默认行为时首选自动生成的特殊成员函数而不是空函数体。你可以通过显式默认设置特殊成员函数,或通过不声明它(也不声明其他会阻止它自动生成的特殊成员函数),来实现此目的。
注意
Visual Studio 不支持默认的移动构造函数或移动赋值运算符作为 C++11 标准授权。有关详细信息,请参阅 支持 C++11/14/17 功能(现代 C++)中的“默认函数和已删除的函数”一节。
已删除的函数
可以删除特殊成员函数以及普通成员函数和非成员函数,以阻止定义或调用它们。通过删除特殊成员函数,可以更简洁地阻止编译器生成不需要的特殊成员函数。必须在声明函数时将其删除;不能在这之后通过声明一个函数然后不再使用的方式来将其删除。

struct widget
{
 // deleted operator new prevents widget from being dynamically allocated.
 void* operator new(std::size_t) = delete;
};
</div>

删除普通成员函数或非成员函数可阻止有问题的类型提升导致调用意外函数。这可发挥作用的原因是,已删除的函数仍参与重载决策,并提供比提升类型之后可能调用的函数更好的匹配。函数调用将解析为更具体的但可删除的函数,并会导致编译器错误。

// deleted overload prevents call through type promotion of float to double from succeeding.
void call_with_true_double_only(float) =delete;
void call_with_true_double_only(double param) { return; }
</div>

请注意,在前面的示例中,使用 call_with_true_double_only 参数调用 float 将导致编译器错误,但使用 call_with_true_double_only 参数调用 int 不会导致编译器错误;在 int 示例中,此参数将从 int 提升到 double,并成功调用函数的 double 版本,即使这可能并不是预期目的。若要确保使用非双精度参数对此函数进行的任何调用均会导致编译器错误,您可以声明已删除的函数的模板版本。

template < typename T >


void call_with_true_double_only(T) =delete; //prevent call through type promotion of any T to double from succeeding.

void call_with_true_double_only(double param) { return; } // also define for const double, double&, etc. as needed.

</div> </div>
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++ 中函数重载、覆盖与隐藏详解
  • C++中函数重载实例详解
  • C++模版函数详解
  • c++中虚函数的实现详解
  • C++函数重载详解及实例代码
  • 详解设计模式中的中介者模式在C++编程中的运用
  • 详解C++中new运算符和delete运算符的使用
  • 详解C++编程中向函数传递引用参数的用法
  • 详解C++编程中数组的基本用法
  • 详解C++编程中的嵌套类的声明与其中的函数使用

相关文章

  • 2017-05-28c++非变易算法-stl算法
  • 2017-05-28C++中构造函数与析构函数的调用顺序详解
  • 2017-05-28c++重载的详细总结
  • 2017-05-28浅谈C++基类的析构函数为虚函数
  • 2017-05-28华为面试题答案找出最大长度子字符串
  • 2017-05-28MFC控件之CListCtrl的应用实例教程
  • 2017-05-28一般函数指针和类的成员函数指针深入解析
  • 2017-05-28C语言实现最长递增子序列问题的解决方法
  • 2017-05-28深入分析Linux下如何对C语言进行编程
  • 2017-09-12c语言 time.h 详细介绍

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C语言数据结构二叉树简单应用
    • 基于C/C++ 常见误区详解
    • Objective-C 消息传递机制详解
    • C语言实现输入一颗二元查找树并将该树转换为它的镜像
    • C++ 中实现把EXCEL的数据导入数据库(ACCESS、MSSQL等)实例代码
    • 简单掌握Linux系统中fork()函数创建子进程的用法
    • 用c语言根据可变参数合成字符串的实现代码
    • 用C语言的泛型实现交换两个变量值
    • Linux中使用C语言的fork()函数创建子进程的实例教程
    • C 语言进制之间的转换

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有