Qt对象模型之二:对象树与元对象系统
一、对象树的概念
Qt中使用对象树(object tree)来组织和管理所有的QObject类及其子类的对象。当创建一个QObject时,如果使用了其他的对象作为其父对象(parent),那么这个 QObject就会被添加到父对象的children()列表中,这样当父对象被销毁时,这个QObject也会被销毁。实践表明,这个机制非常适合于管理GUI对象。例如,一个 QShortcut(键盘快捷键)对象是相应窗口的一个子对象,所以当用户关闭了这个窗口 时,这个快捷键也可以被销毁。
QWidget作为能够在屏幕上显示的所有部件的基类,扩展了对象间的父子关系。 一个子对象一般也就是一个子部件,因为它们要显示在父部件的区域之中。例如,当关闭一个消息对话框(message box)后要销毁它时,消息对话框中的按钮和标签也会被销毁,这也正是我们所希望的,因为按钮和标签是消息对话框的子部件。当然,也可以自己来销毁一个子对象。关于这一部分内容,可以在帮助索引中査看Object Trees & Ownership关键字。
二、对象树的示例程序
新建Qt Gui应用,项目名称为myOwnership,基类选择QWidget,然后类名保持Widget不变。完成后向项目中添加新文件,模板选择C+ +类,类名为MyButton,基类为QPushButton,类型信息选择“继 承自QWidget”。添加完文件后将mybuuon. h文件修改如下:
#ifndef MYBUTTON_H
#define MYBUTTON_H
#include <QPushButton>
#include <QDebug>
class MyButton : public QPushButton
{
Q_OBJECT
public:
explicit MyButton(QWidget *parent = nullptr);
~MyButton();
};
#endif // MYBUTTON_H
这里主要是添加了析构函数的声明。然后到mybutton. cpp文件中,修改如下:
#include "mybutton.h"
MyButton::MyButton(QWidget *parent) :
QPushButton(parent)
{
}
MyButton::~MyButton()
{
qDebug() << "delete button";
}
这里添加了析构函数的定义,这样当 MyButton 的对象被销毁时,就会输出相应的信息。
下面到widget.cpp文件中,修改如下:
#include "widget.h"
#include "ui_widget.h"
#include "mybutton.h"
#include <QDebug>
#include <QHBoxLayout>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//创建按钮部件,指定widget为父部件
MyButton *button = new MyButton(this);
button->setText(tr("button"));
}
Widget::~Widget()
{
delete ui;
qDebug() << "delete widget";
}
当Widget窗口被销毁时,将输出信息。下面运行程序,然后关闭窗口,在Qt Creator的应用程序输出栏中的输出信息为:
delete widget
delete button
可以看到,当关闭窗口后,因为该窗口是顶层窗口,所以应用程序要销毁该窗口部件(如果不是顶层窗口,那么关闭时只是隐藏,不会被销毁),而当窗口部件销毁时会自动销毁其子部件。这也就是为什么在Qt中经常只看到new操作而看不到delete操作 的原因。
再来看一下main.cpp文件,其中Widget对象是建立在栈上的:
Widget w;
w.show();
这样对于对象w,在关闭程序时会自动销毁。而对于Widget中的部件,如果是在堆上创建(使用new操作符),那么只要指定Widget为其父窗口就可以了,也不需要进行delete操作。当对象w销毁时会自动销毁它的所有子部件,这些都是Qt的对象树所完成的。
所以,对于规范的Qt程序,我们要在main()函数中将主窗口部件创建在栈上,例如“Widget w;”,而不要在堆上进行创建(使用new操作符)。对于其他窗口部件,可以使用new操作符在堆上进行创建,不过一定要指定其父部件,这样就不用使用delete操作符来销毁该对象了。
三、元对象系统的概念
Qt中的元对象系统(Meta-Object System)提供了对象间通信的信号和槽机制、运行时类型信息和动态属性系统。元对象系统是基于以下3个条件的:
- 该类必须继承自QObject类;
- 必须在类的私有声明区声明Q_OBJECT宏(在类定义时,如果没有指定public或者private,则默认为private);
- 元对象编译器Meta-Object Compiler(moc),为QObject的子类实现元对象特性提供必要的代码。
其中,moc工具读取一个C+ +源文件,如果它发现一个或者多个类的声明中包含有Q_OBJECT宏,便会另外创建一个C+ +源文件(就是在项目目录中的debug目录 下看到的以moc开头的C+ +源文件),其中包含了为每一个类生成的元对象代码。 这些产生的源文件或者被包含进类的源文件中,或者和类的实现同时进行编译和链接。
元对象系统主要是为了实现信号和槽机制才被引入的,不过除了信号和槽机制以外,元对象系统还提供了其他一些特性:
- QObjeCt::metaObject()函数可以返回一个类的元对象,它是QMetaObject类的对象;
- QMetaObject::className()可以在运行时以字符串形式返回类名,而不需要C+ +编辑器原生的运行时类型信息(RTTI)的支持;
- QObject:: “inherits()函数返回一个对象是否是QObject继承树上一个类的实例的信息;
- QObject: :tr()和QObject: :trUtf8()迸行字符串翻译来实现国际化;
- QObject::setProperty()和QObject::property()通过名字来动态设置或者获取对象属性;
- QMetaObject: :newlnstance()构造该类的一个新实例。
除了这些特性,还可以使用qobject_cast()函数来对QObject类进行动态类型转换,这个函数的功能类似于标准C+ +中的dynamic_cast()函数,但它不再需要RTTI的支持。这个函数尝试将它的参数转换为尖括号中的类型的指针,如果是正确的类型,则返回一个非零的指针,如果类型不兼容则返回0。例如:
QObject *obj = new MyWidget;
QWidget *widget = qobject_cast<QWidget *>(obj);
信号和槽机制是Qt的核心内容,而信号和槽机制必须依赖于元对象系统,所以它是Qt中很关键的内容。这里只是说明了它的一些应用,关于它的具体实现机制,这里不再讲述。关于元对象系统的具体描述,可以在Qt中查看The Meta Object System关键字。
Qt对象模型之二:对象树与元对象系统的更多相关文章
- 解析Qt元对象系统(四) 属性系统(确实比较方便)
官方解释 我们在Qt源码中可以看到一个QObject的子类经常会用到一些Q_开头的宏,例如QMainWindow类开始部分代码是这样的: Q_PROPERTY(QSize iconSize READ ...
- QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)
作者:小豆君的干货铺链接:https://www.zhihu.com/question/27040542/answer/218384474来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...
- QT从入门到入土(二)——对象模型(对象树)和窗口坐标体系
摘要 我们使用的标准 C++,其设计的对象模型虽然已经提供了非常高效的 RTTI 支持,但是在某些方面还是不够灵活.比如在 GUI 编程方面,既需要高效的运行效率也需要强大的灵活性,诸如删除某窗口时可 ...
- QT Embedded二三事之QObject的元对象
一.元对象 元对象被称做是meta object.在运行时刻(runtime),能够提供对象的运行时信息. 在C++语言发展的早期,C++语言本身没有定义对象的运行时信息,如输出类的名 ...
- Qt信号槽机制的实现(面试的感悟,猜测每一个类保存的一个信号和槽的二维表,实际使用函数指针 元对象 还有类型安全的检查设定等等)
因为面试时问了我这道题,导致我想去了解信号槽到底是如何实现的,于是贴着顺序看了下源码,大致了解了整个框架.网上关于信号槽的文章也很多,但是大部分都是将如何应用的,这里我就写一下我所理解的如何实现吧, ...
- 深入了解Qt(二)之元对象系统(Meta-Object System)
深入了解Qt主要内容来源于Inside Qt系列,本文做了部分删改,以便于理解.在此向原作者表示感谢! 在Qt Meta Object System-元对象系统这篇文章中,从底层实现的源码剖析了元对象 ...
- Qt——元对象和属性机制
http://www.cnblogs.com/hellovenus/p/5582521.html 一.元对象 元对象(meta object)意思是描述另一个对象结构的对象,比如获得一个对象有多少成员 ...
- Qt根据类名创建对象(元对象反射)
在java语言中,可以使用getObject(String)函数,从类名直接构建新的对象. 而在C++中是没有这种机制的,Qt虽然提供了元对象机制,但只可以获取对象的类名,不能反向构建. 这个问题我在 ...
- Qt对象树
Qt提供了一种机制,能够自动.有效的组织和管理继承自QObject的Qt对象,这种机制就是对象树.子对象动态分配空间不需要释放.
随机推荐
- Maven创建项目时出现Generating project in Interactive mode就一直卡住的解决方案
使用maven命令在创建项目的时候出现 Generating project in Interactive mode 然后就一直卡住 网上搜做了很多解决方案 有说各种方案的,最后找到了一种.实验成功 ...
- Linux中断处理驱动程序编写
本章节我们一起来探讨一下Linux中的中断 中断与定时器:中断的概念:指CPU在执行过程中,出现某些突发事件急待处理,CPU暂停执行当前程序,转去处理突发事件,处理完后CPU又返回原程序被中断的位置继 ...
- samba.conf (香港中华厨房有限公司实例)
# Sample configuration file for the Samba suite for Debian GNU/Linux. # # This is the main Samba con ...
- iOS设计模式 - (1)概述
近期可自由安排的时间比較多, iOS应用方面, 没什么好点子, 就先放下, 不写了.花点时间学学设计模式. 之后将会写一系列博文, 记录设计模式学习过程. 当然, 由于我自己是搞iOS的, 所以之后设 ...
- 9.Laravel5学习笔记:在laravel中注冊自己的服务到容器中
问题描写叙述 或许标题写的不够清楚.实际情况是,在我使用laravel的过程中.须要将自己的一个类,通过服务提供者注冊到IOC容器中,可是在实际操作过程中.出现了下面错误: Unresolvable ...
- http协议的相关知识
因为如今的工作设计的Web开发,因此了解了一下Http协议.在阅读了这篇文章HTTP协议具体解释(真的非常经典)后,总结了相关经常使用知识并列在此处以方便以后的查询. HTTP协议的主要特点可概括例如 ...
- 论持久战之PHPStorm Xdebug Remote 调试环境搭建(不依赖本地环境)
最近公司自己搭建了一个资源管理平台,哈哈,当然是我在github上找的,后台用PHP开发.个人觉得写得非常nice,web页面几乎模拟了真实OS,有兴趣的朋友下载部署体验https://github. ...
- xcode 程序配置 python 解释器嵌入
1.点击项目->Buid Phases->加号点击 添加RunScript,Shell中写为python路径.一般是/usr/bin/python 2.同样是Build Phases中,L ...
- 判断一个包是否可以安装是一个NP-complete问题
1 checking whether a single package P can be installed, given a repository R,is NP-complete
- Swift入门(十)——循环引用、弱引用和无主引用
近期看到swift里面不仅有循环引用和弱引用(weak),还加入了无主引用(unowned),于是写了一些demo,这里总结一下. 和OC一样.Swfit默认也是基于ARC进行内存管理的,因此尽管简单 ...