一、QObject概述

QObject类是QT的核心,大部分QT类都是从这个类直接或者间接继承而来。包含QT的信号槽机制和事件机制

QObject通过对象树将对象组织起来,当使用QObject创建一个对象作为其他对象的父对象时,QObject对象会将其他对象自动添加到子对象的列表中,注意,这里的对象数和父子对象关系不是C++里面的父类和子类的关系,只是一种单纯的树型组织结构

二、QObject的数据存储

QObject 类的相关文件一共有四个:

qobject.h,QObject class定义的头文件

qobject.cpp,QObject class 和QMetaObject class的实现文件,实现了signal、slot、properties等核心部分

qobjectdefs.h,定义了 QMetaObject class。

qobject_p.h,定义了 QObjectPrivate 类,用来存储 QOjbect 对象的成员数据。

先看下qobject.h

class Q_CORE_EXPORT QObject
{Q_DECLARE_PRIVATE(QObject)
public:Q_INVOKABLE explicit QObject(QObject *parent=nullptr);virtual ~QObject();//......
protected:QObject(QObjectPrivate &dd, QObject *parent = nullptr);QScopedPointer<QObjectData> d_ptr;
};class Q_CORE_EXPORT QObjectData {Q_DISABLE_COPY(QObjectData)
public:QObjectData() = default;virtual ~QObjectData() = 0;//......
};

Q_DISABLE_COPY在qglobal.h中,实现如下

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

主要是为了防止QObjectData被拷贝和赋值

qobject.h中,定义了QObject和QObjectData两个类,QObjectData用来存储QObject的数据,并且在QObject被定义为智能指针d_ptr,QScopedPointer保证当指向对象离开作用域后,指向的对象将被删除。防止内存泄露

Q_DECLARE_PRIVATE在qglobal.h中,实现如下

#define Q_DECLARE_PRIVATE(Class) \inline Class##Private* d_func() \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \inline const Class##Private* d_func() const \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \friend class Class##Private;

Class##Private中的##的作用是连接,当传入QObject后,Class##Private就变成QObjectPrivate

所以,Q_DECLARE_PRIVATE(QObject)展开后代码如下:

#define Q_DECLARE_PRIVATE(Class) \inline QObjectPrivate* d_func() \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<QObjectPrivate *>(qGetPtrHelper(d_ptr));) } \inline const QObjectPrivate* d_func() const \{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const QObjectPrivate *>(qGetPtrHelper(d_ptr));) } \friend class QObjectPrivate;

其中的qGetPtrHelper是个模板函数

template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) -> decltype(ptr.operator->()) { return ptr.operator->(); }

所以,如果class是QObject,d_func的作用就是将QObject对象的指针转化为QObjectPrivate的指针

而QObjectPrivate在qobject_p.h中定义

class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{Q_DECLARE_PUBLIC(QObject)QObjectPrivate(int version = QObjectPrivateVersion);virtual ~QObjectPrivate();//下面是signal 和slot 的数据,属性数据等
};

QObjectPrivate继承了QObjectData,由于QObjectData是个纯虚类,所以具体的实现在QObjectPrivate中

而在QObject的构造函数中,将QObjectData的指针d_ptr初始化为QObjectPrivate

QObject::QObject(QObject *parent): d_ptr(new QObjectPrivate)
{//......
}QObject::QObject(QObjectPrivate &dd, QObject *parent): d_ptr(&dd)
{//......
}

以具体的QWidget为例,QWidget的定义如下,在qwidget.h的头文件中

class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice
{Q_OBJECTQ_DECLARE_PRIVATE(QWidget)explicit QWidget(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());//private构造,防止对QWidget进行拷贝和赋值~QWidget();//......
};

QWidget公有继承了QObject

QWidget构造函数的具体实现如下:

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f): QObject(*new QWidgetPrivate, 0), QPaintDevice()
{QT_TRY {d_func()->init(parent, f);} QT_CATCH(...) {QWidgetExceptionCleaner::cleanup(this, d_func());QT_RETHROW;}
}/*! \internal*/
QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f): QObject(dd, 0), QPaintDevice()
{Q_D(QWidget);QT_TRY {d->init(parent, f);} QT_CATCH(...) {QWidgetExceptionCleaner::cleanup(this, d_func());QT_RETHROW;}
}

这两个构造函数都调用了基类QObject的对应的构造函数,并以QWidgetPrivate的对象和指针作为第一个参数传进去。然后调用init函数,d_func()返回的是d_ptr,是QObjectPrivate的指针,而QObjectPrivate是QWidgetPrivate的基类,代码如下

class Q_WIDGETS_EXPORT QWidgetPrivate : public QObjectPrivate
{Q_DECLARE_PUBLIC(QWidget)
public:explicit QWidgetPrivate(int version = QObjectPrivateVersion);~QWidgetPrivate();
};

所以,基类(QObject)中的d_ptr指针将会指向一个QWidgetPrivate类型的对象,dd将和QWidgetPrivate对象绑定,从而最终调用QWidgetPrivate中的init函数。

所以,通过上述的分析可知,在QT中,QObject类和数据分别是通过两个类QObject和QObjectData来封装的,然后QObjectPrivate又继承了QObjectData,实现了QObjectData中的一部分功能

当要创建一个具体的QT对象时,比如QWidget,会先调用父类QObject构造函数,然后通过C++的多态机制将QWidget的数据部分QWidgetPrivate传入父类QObject的构造函数,从而使对象父类QObject中的数据指针:d_ptr(QObjectPrivate类型的)指向对象的数据QWidgetPrivate,然后就可以使用或操作具体对象的数据了

将类和类的数据分别封装在两个类中,使得类本身和类数据的封装性更好,降低了类数据和类本身之间的耦合

参考

Inside Qt Series

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

0.QObject的数据存储相关推荐

  1. Python爬取数据存储到本地文本文件

    前面说过Python爬取的数据可以存储到文件.关系型数据库.非关系型数据库.前面两篇文章没看的,可快速戳这里查看!https://mp.weixin.qq.com/s/A-qry4r3ymuCLXLB ...

  2. Matchvs多种数据存储接口对比分析

    Matchvs 给开发者提供了三种存储接口:用户数据存储.全局数据存储.哈希存储. 三种数据存储的特点及对比如下: 用户数据存储,存储用户数据,只有用户自己有增.删.改.查自己数据的权限 全局数据存储 ...

  3. 基于Python操作将数据存储到本地文件

    点击蓝字 关注我们 前面说过Python爬取的数据可以存储到文件.关系型数据库.非关系型数据库.前面两篇文章没看的,可快速戳这里查看!<使用Python将数据存入SQLite3数据库> & ...

  4. AS3.0编程 So本地数据存储(“超级cookies”)--AS3:Local SharedObject

    Flash影片运行过程中,大多数的数据都存储于影片本身,一旦影片被关闭,这些数据也就从内存中被清除掉,下次运行时,数据将从头开始.若想存储数据或者让客户端的多个影片共享同一组数据,就要想办法把数据存储 ...

  5. [转]ActionScript 3.0入门:Hello World、文件读写、数据存储(SharedObject)、与JS互调

    本文转自:http://www.cnblogs.com/artwl/p/3396330.html 近期项目中可能要用到Flash存取数据,并与JS互调,所以就看了一下ActionScript 3.0, ...

  6. Android数据存储之GreenDao 3.0 详解

    前言: 今天一大早收到GreenDao 3.0 正式发布的消息,自从2014年接触GreenDao至今,项目中一直使用GreenDao框架处理数据库操作,本人使用数据库路线 Sqlite----> ...

  7. ActionScript 3.0入门:Hello World、文件读写、数据存储(SharedObject)、与JS互调

    近期项目中可能要用到Flash存取数据,并与JS互调,所以就看了一下ActionScript 3.0,现把学习结果分享一下,希望对新手有帮助. 目录 ActionScript 3.0简介 Hello ...

  8. 从0到1搭建大数据平台之数据存储

    大家好,我是脚丫先生 (o^^o) 近日参加了集团大数据平台之流批一体的建设. 流批一体,从调研直至研发.日日夜夜,泪流满面. 作业以:sql.jar.组件拖拽三种方式去提交实时任务,终究还是攻克. ...

  9. [VPX611]基于 6U VPX 总线架构的SATA3.0 高性能数据存储板

    板卡概述 VPX611 是一款基于6UVPX 总线架构的高性能数据存储板,该板卡采用2 片XilinxKintex-7 系列FPGA 作为主控单元,FPGA 内嵌RAID 控制器,最大支持8 个mSA ...

最新文章

  1. mac下git与github简单使用
  2. JAVA是如何传递参数的?是传值(by value)?还是传地址(by reference)?
  3. SQL中left join、right join、inner join的区别
  4. 4位快速加法器和4位串行加法器相比_使用混合信号示波器调试串行总线系统
  5. Exchange Server 2016管理系列课件50.DAG管理之激活数据库副本
  6. (计算机组成原理)第五章中央处理器-第四节2:微程序控制器基本原理
  7. Elasticsearch aggregations API
  8. 程序员风光背后:从零到BAT数据分析师靠的是什么?
  9. 图片尺寸判断等-我们到底能走多远系列(21)
  10. sap系统ftp服务器下文件,sap ftp服务器
  11. 来给你的CSDN博客换个皮肤~
  12. win10下使用mklink命令给C盘软件搬家
  13. pixel 2 xl的root之旅
  14. 国外android大神博客,Android手机浏览器(国外篇)横向对比评测
  15. C# 文件搜索过程中如何提取office文件,wps,pdf,html,eml等格式的文件正文
  16. 目标跟踪 OP,CLE,DP,AUC的概念和计算
  17. 面试关于网络的那些事
  18. 百度地图自定义吹出框
  19. 小程序源码:百变头像框制作微信小程序源码下载,免服务器和域名
  20. Vscode extensions开发

热门文章

  1. 30分钟,让你彻底明白Promise原理
  2. MVC,MVP 和 MVVM 的图示
  3. 裁剪Linux小系统
  4. Server 2012 Hyper-v新功能之一:客户端 Hyper-V
  5. 安装exchange server 2003服务器
  6. hbctraining-05_peak_calling_macs2
  7. graphviz画图
  8. Python3 list 自定义比较函数
  9. leetcode102 二叉树的层次遍历
  10. ZeroC ICE java异步实现方式(ami/amd)