[学习][笔记] qt5 从入门到入坟:<四>对象模型

简介: [学习][笔记] qt5 从入门到入坟:<四>对象模型

对象模型

moc (Meta Object Compiler,元对象编译器)

moc 为了解决某些特定问题域下的静态特性 和 GUI 界面需要同时具有运行时的效率以及更高级别的灵活性。

Qt “扩展”了标准C++。所谓“扩展”,实际是在使用标准 C++ 编译器编译 Qt 源程序之前,Qt 先使用一个叫做 moc(Meta ObjectCompiler,元对象编译器)的工具,先对 Qt 源代码进行一次预处理(注意,这个预处理与标准 C++ 的预处理有所不同。Qt 的 moc预处理发生在标准 C++ 预处理器工作之前,并且 Qt 的 moc 预处理不是递归的。),生成标准 C++ 源代码,然后再使用标准 C++编译器进行编译。

例如信号槽,c++标准不支持的但是却可以编译通过。

Qt 使用 moc,为标准 C++ 增加了一些特性:

信号槽机制,用于解决对象之间的通讯,这个我们已经了解过了,可以认为是 Qt 最明显的特性之一; 可查询,并且可设计的对象属性;

强大的事件机制以及事件过滤器; 基于上下文的字符串翻译机制(国际化),也就是 tr() 函数,我们简单地介绍过;

复杂的定时器实现,用于在事件驱动的 GUI 中嵌入能够精确控制的任务集成; 层次化的可查询的对象树,提供一种自然的方式管理对象关系。

智能指针(QPointer),在对象析构之后自动设为 0,防止野指针; 能够跨越库边界的动态转换机制。

通过继承QObject类,我们可以很方便地获得这些特性。 当然,这些特性都是由 moc 帮助我们实现的。moc

其实实现的是一个叫做元对象系统(meta-object system)的机制。正如上面所说,这是一个标准 C++ 的扩展,使得标准 C++

更适合于进行 GUI 编程。虽然利用模板可以达到类似的效果,但是 Qt 没有选择使用模板。按照 Qt

官方的说法,模板虽然是内置语言特性,但是其语法实在是复杂,并且由于 GUI 是动态的,利用静态的模板机制有时候很难处理。而自己使用 moc

生成代码更为灵活,虽然效率有些降低(一个信号槽的调用大约相当于四个模板函数调用),不过在现代计算机上,这点性能损耗实在是可以忽略。

对象树

QObject

QObject是以对象树的形式建立的,QObject对象创建的时候,构造方法需要传入parent,当前QObject作为该parent的children其中的一个孩子。当parent销毁时parent的children也会销毁。

例如,一个QButton(按钮)有一个QShortcut(快捷键)对象作为其子对象。当我们删除按钮的时候,这个快捷键理应被删除。这是合理的。

对于控件QWindow和QDialog 如果parent 为 NULL,则该对话框会作为一个顶层窗口,否则则作为其父组件的子对话框。

QWidget

QWidget是能够在屏幕上显示的一切组件的父类。QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。

当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。

我们可以使用QObject::dumpObjectTree()和QObject::dumpObjectInfo()这两个函数进行这方面的调试。

Qt 的对象树机制虽然帮助我们在一定程度上解决了内存问题,但是也引入了一些值得注意的事情。

当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。

不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。

Qt 保证的是,任何对象树中的 QObject对象delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。

当一个QObject对象在栈上创建的时候,就需要注意父子创建顺序问题。

{
    QWidget window;
    QPushButton quit("Quit", &window);
}

解释以上:windows先创建后销毁,quit后创建先销毁调用析构,将自己从父对象 window 的子对象列表中删除,然后再销毁windows,调用windows析构。不会造成quit析构两次问题。

但是下面:

{
    QPushButton quit("Quit");
    QWidget window;
    quit.setParent(&window);
}

quit先创建后销毁,window后创建先销毁,window销毁时调用析构时会先析沟子对象列表。然后quit又一次因为超出作用域而析构时,会造成第二次析沟导致问题。

Qt 学习之路 2(10):对象模型

目录
打赏
0
0
0
0
44
分享
相关文章
【QT速成】半小时入门QT6之QT前置知识扫盲(二)
【QT速成】半小时入门QT6之QT前置知识扫盲(二)
249 13
【QT速成】半小时入门QT6之QT前置知识扫盲(一)
【QT速成】半小时入门QT6之QT前置知识扫盲(一)
277 2
【QT速成】半小时入门QT6之QT前置知识扫盲(二)
【QT速成】半小时入门QT6之QT前置知识扫盲(二)
150 2
dynamic-situational-awareness-qt学习记录
本文是作者yantuguiguziPGJ关于dynamic-situational-awareness-qt学习记录的分享,介绍了在Qt学习过程中发现的qml资源丰富的代码仓库,并提供了资源路径和相关的安装、配置步骤,涉及的内容有数字地球、GIS纹理等,同时提供了相关链接和git命令来克隆代码仓库和ArcGIS Runtime SDK for Qt的安装说明。
【QT速成】半小时入门QT6之QT前置知识扫盲(一)
【QT速成】半小时入门QT6之QT前置知识扫盲(一)
361 0
Qt注册类对象单例与单类型区别
在进行开发时,应当根据具体的应用场景和需求来选择使用单例模式或是单类型。如果是全局服务或状态管理,可能需要单例模式;如果是为了使QML环境下的不同组件能够访问到同一个后端服务对象,则可能需要使用单类型。
92 2
|
9月前
|
C++
Qt中的信号与槽如何学习?(包括自定义信号)这篇文章告诉你
以现实中的事件来举例的话,例如有两把不同颜色的信号枪,分别是红色,绿色,打响不通颜色的信号枪会触发不同的槽发生,比如说打响红色这个人就跑步,绿色就走步,但是还有一个很重要的机制,那就是连接,我们需要把信号枪去跟这个人的动作连接起来。 如果上面理解没问题的话我们可以把信号和槽看成两个工具,我们最重要的是如何去把这两个工具连接起来。 它的作用可以让我们更加灵活的去使用不同窗口间的切换以及某些事件的连接。
143 0
Qt中的事件该如何学习?(附带案例)
事件是Qt中比较重要的一部分,在初期如果理解不当学习可能会比较困难,这里提一嘴当初教我的那位老师水平是真的高,让我很轻易的就理解了事件的概念。 在平时我们见到那些界面上的某些快捷键就有可能是事件做的,例如ESC关闭窗口,Enter提交或者登录这种类似的,这也是事件的强大之处。
196 0
|
10月前
|
技术笔记:Qt基础之配置文件(QSettings)
技术笔记:Qt基础之配置文件(QSettings)
577 0
|
10月前
|
技术笔记:QT之深入理解QThread
技术笔记:QT之深入理解QThread
102 0

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等