本文翻译自: https://www.cleanqt.io/blog/why-qobject-subclasses-are-not-copyable
原作者: Alexander Fagrell
原文发布时间:2018年8月14日

如果您尝试复制QObject派生的类,则会导致编译器错误,例如:

class MyClass : public QObject {Q_OBJECT
} my_class;auto my_class_copy = my_class;

使用Qt5并使用C++11(支持=delete):

错误:使用已删除的函数’MyClass::MyClass(const MyClass&)’

或更早版本:

错误:'QObject::QObject(const QObject&)'在此上下文中是私有的。

此行为是设计使然。但是为什么要删除复制构造函数(以及赋值运算符)?如果您仍要复制该怎么办?如果它不可复制,那么它可以移动吗?以下文章将研究这些问题,并探讨在自定义子类中重复删除操作是否是一种好习惯。就让我们一探究竟吧!

不能复制QObject有几个原因。其中两个最大的原因是:

  • QObjects之间通常使用信号和槽机制进行通信。不清楚连接的信号和/或插槽是否应该转移到副本。如果它们将被转移,则意味着其他qobject将自动订阅该副本。这很可能会给开发人员带来混乱和不必要的副作用。
  • QObjects被组织在对象树中。通常一个QObject的一个实例有一个父对象和几个子对象。在这个层次结构中副本应该组织在哪里?孩子(和孙子……)也应该被复制吗?

其他原因,但可能不那么重要,是:

  • 一个QObject可以被认为是唯一的,方法是给它一个可以用作参考键的名称,即通过设置QObject::objectName()。如果设置了名称,则不清楚应该为副本指定哪个名称。
  • QObjects可以在运行时使用新的属性进行扩展。副本是否也应该继承这些新属性?

一般来说,QObjects是通过它们的指针地址被其他对象引用的。例如,前面提到的信号和槽机制就是这种情况。因此,QObjects无法移动;他们之间的联系就会消失。在QObject的源代码中,我们可以看到没有声明move构造函数或move赋值运算符。但是,由于复制构造函数被删除,所以不会隐式地生成move构造函数,如果开发人员试图移动QObject,就会报编译器错误。

因此,您不能复制,也不能移动QObject,但是如果要复制底层数据(或属性)怎么办?Qt的文档在Qt对象模型中区分了两种对象类型:值对象和身份对象。值对象,如:QSize,QColor和QString是可被复制和分配的对象。相反,身份对象无法复制,但可以克隆。您可能已经猜到过,身份对象的一个示例是QOBject或从其派生的任何类。克隆的含义可以从官方文档中读取:

克隆意味着创建一个新的身份,而不是旧身份的完全副本。例如,双胞胎有不同的身份。他们可能看起来一样,但是他们有不同的名字,不同的地点,可能有完全不同的社交网络。

我对克隆的理解是,你可以在一个子类中暴露一个clone()函数,它创建了一个新的身份,但不是一个真正的副本,即:

class MyClass : public QObject {Q_OBJECTpublic:MyClass* clone() {auto copy = new MyClass;//copy only datareturn copy;}private://data
};
...auto my_class = new MyClass;
auto my_class_clone = my_class->clone();

虽然这是可能做到的,但我不建议这样做。这可能会导致不必要的副作用,因为Qt开发人员很可能对QObject有一些假设。如果您需要创建一个克隆,我建议您查看一下您的总体设计和体系结构。也许数据可以解耦或分解?

Q_DISABLE_COPY(Class)在子类中重复

在stackoverflow帖子建议总是在你自己的类中重新声明宏Q_DISABLE_COPY(Class),即:

class MyClass : public QObject {Q_OBJECTQ_DISABLE_COPY(MyClass) // See macro belowpublic:QObject() {}
};

注:(stackoverflow帖子https://stackoverflow.com/questions/19854371/repeating-q-disable-copy-in-qobject-derived-classes)

#define Q_DISABLE_COPY(Class) Class(const Class &); Class &operator=(const Class &);

正如stackoverflow帖子中所述,主要原因是为了**改善错误信息*。如果没有宏,则使用Qt4报告以下错误信息:

错误:'QObject::QObject(const QObject&)'在此上下文中是私有的。

使用宏,将会报以下错误信息:

错误:'MyClass::MyClass (const MyClass&)'在此上下文中是私有的。

对于Qt的新手来说,最后一条错误消息要容易得多。

但是从Qt5开始,宏被更改并声明为:

#ifdef Q_COMPILER_DELETE_MEMBERS
# define Q_DECL_EQ_DELETE = delete
#else
# define Q_DECL_EQ_DELETE
#endif#define Q_DISABLE_COPY(Class) Class(const Class &) Q_DECL_EQ_DELETE;Class &operator=(const Class &) Q_DECL_EQ_DELETE;

不在子类中添加宏,则显示以下错误消息:

错误:使用已删除的函数’MyClass::MyClass (const MyClass&)’。

复制构造函数和赋值操作符使用=delete声明,而不再是声明私有,从而产生了一个首选的错误消息。

即使错误消息已得到改善,我仍然相信在派生类中重新声明宏是有价值的,因为它记录了类的行为。刚接触Qt的人可以快速理解其用法:不应(也不能)复制对象!​

qt自带的文档系统软件叫什么名字_翻译 | 为什么QObject子类不可复制?相关推荐

  1. c#erp项目源码 mysql_Jsp+Ssm+Mysql实现图书馆预约占座管理系统项目源码(可带论文文档)...

    JSP+SSM+MYSQL实现图书馆预约占座管理系统项目源码(可带论文文档). 一款ssm图书馆预约占座管理系统,此系统有论文文档,需单独购买,此商品只为项目源码. 提前预定的好处:一开始我们这边有大 ...

  2. 市面售价2W的仿抖音短视频原生双端APP源码,带技术文档管理后台和数据库

    这个短视频系统源码是2w某站购买来的仿抖音视频app,原生双端开发,带技术文档管理后台和数据库.非常适合用来做类似项目的基础开发框架,能节省大量的开发时间和试错成本. 除了直播没有开通,其他功能都是精 ...

  3. wps文档漫游删除_WPS自带的文档漫游和在线模板怎么关闭?

    也可以直接在注册表编辑器选择编辑查找查找目标中输入roaminghomepageguidedtag. 按确定后,(如第四幅图) 如果希望再次显示文档漫游,关闭文档, 方法一:在cmd(命令提示符)中输 ...

  4. 【源码分享】ASP.NET大型快运(快递)管理系统带完整文档

    ASP.NET大型快运(快递)管理系统源码带完整文档 大型快递(快运)管理系统基于webservice的分布式系统,集成快递物流业务流程管理,快递物流公司内部管理,快递物流单全网跟踪监控,并集成基于w ...

  5. ASP.NET大型快运(快递)ERP系统带完整文档【源码分享】

    ASP.NET大型快运(快递)管理系统源码带完整文档 源码分享,需要源码学习参考可私信我. 大型快递(快运)管理系统基于webservice的分布式系统,集成快递物流业务流程管理,快递物流公司内部管理 ...

  6. 分享一套完整的汽车维修订单管理系统源码 带数据库文档

    完整的汽车维修管理系统源码带数据库文档 开发环境为Microsoft Visual Studio 2012以上版本,数据库为SQLServer2008 R2,使用C#语言开发. 一个完整的汽车维修管理 ...

  7. PHP在线模拟考试系统源码(带操作文档)源码分享

    PHP在线模拟考试系统源码带操作文档 源码全开源免费分享, 在线考试系统将传统的培训考试与先进的网络模式相结合,使用户可根据自身特点快速构建考试.测评.练习.竞赛.调查.分析及管理 于一体的网络化考试 ...

  8. 新鲜出炉的React博客系统源码,极简主义设计,手机端可自适应,超级简单,带部署文档与演示视频加截图

    新鲜出炉的React博客系统源码,极简主义设计,手机端可自适应,超级简单,带部署文档与演示视频加截图. 使用技术: 客户端前端:Next.js + React 管理端前端:React + Ant De ...

  9. 如何在线查看Android源码自带学习文档

          如何在线查看Android源码自带学习文档docs Android源码编译系列博客: Android.bp你真的了解吗 Android.bp入门指南之Android.mk转换成Androi ...

最新文章

  1. 软考总结——虚存管理
  2. java获取当前路径
  3. oracle查看用户密码时间限制
  4. wxWidgets:wxRibbonButtonBar类用法
  5. C0302 将一个代码块中的内容保存在文件中, 查看一个rpm包是否可以安装
  6. SPARK:作业基本运行原理
  7. stata主成分分析_主成分分析在STATA中的实现
  8. 【EI/Scopus检索】计算机主题征稿,AANN 2021诚邀您投稿参会!
  9. 常用的工业控制计算机有哪几类,工业控制计算机在行业应用中都有哪些特点?...
  10. JRebel出现ERROR Failed to obtain seat. Unable to connect to license server
  11. 保研之路——北邮网研院交换中心夏令营
  12. 分布式游戏服务器设计
  13. VUCA时代的领导力开发
  14. win10升级系统版本的步骤,win10电脑如何升级系统版本
  15. (4)pokeman_用图片对模型进行测试
  16. 3D Models (3D 模型)
  17. 借助阿里云轻松部署企业网盘
  18. 10个谈话技巧让你平步青云
  19. 批量 汉字 转 拼音方法
  20. 计算机专业相关的职业技术证书有哪些,你知道吗?

热门文章

  1. 数据治理注意哪些问题
  2. 合适的大数据安全分析平台如何选择
  3. 中琛源主要的产品是什么
  4. ios java aes_PHP7 AES加密解密函数_兼容ios/andriod/java对等加解密
  5. android+wear独立应用,谷歌更新Android Wear政策:鼓励开发可独立运行的手表应用
  6. AcWing 848. 有向图的拓扑序列(拓扑排序模板)
  7. react多个网络请求_react中网络请求的优化!
  8. 唯一的确定一棵二叉树
  9. Twisted入门教程(10)
  10. Unity3D导出的EXE不用显示分辨率选择界面