今天在看QT对象内存管理的一篇文章时:
http://blog.csdn.net/dbzhang800/article/details/6300025
想到了一个问题:就是QT类库体系结构与Delphi类库体系结构的对比问题。从它们都有parent属性,而且都可以管理子控件的内存释放,就可以猜测两者的体系结构十分相似。以下是我的过程,就把它当自己对Qobject和QWidget的一个熟悉过程吧。

---------------------------------------------------------------------------

先看它们的继承体系:

Delphi的TApplication->TComponent->TPersistent->TObject
QT的QApplication->QCoreApplication->QObject
注意,它直接继承自QObject,而省略了delphi的两个层次:TComponent和TPersistent
因此特意查看了一下,QObject已经包括了setParent,非常类似于TComponent的InsertComponent(owner)
QObject的setObjectName相当于TComponent的setName。这样一来,QObject即已经包括了TComponent的主要功能。

但是QObject貌似没有TPersistent的RTTI和流入流出的功能。不过不要紧,因为C++标准里就包括了RTTI和流入流出的功能,因此不需要在类库里体现这一点,而是随时随地可用的。而Delphi因为自成一体,语言和类库结合的过于紧密,不得不单独定义一层TPersistent来提供相应的功能(也就是说,不使用VCL的object pascal是没有RTTI和流入流出功能的)。

这么说来,一个QObject就已经包括了Delphi的TObject、TPersistent和TComponent这三个类层次的功能。并且QObject还多了对signal的管理,tr的功能。

而且还有一个最大的区别是从QObject开始就处理事件的方方面面,connect,过滤,阻塞,并且专门提供了一大堆相关的附加功能。Delphi虽然也可使用Dispatch把消息发给TObject,但事实上没有人这样使用。

此外,QObject还提供了deleteLater功能,即自删除。这可是没有父类控件的情况下提供的哦~

还有一个特点:QObject竟然是从属于某个线程的,而且专门提供了2个函数:thread()和moveToThread()。而其它语言包括Delphi的Object都没有这个特征。究其原因,是因为QT把信号槽机制放在QObject级了,换而言之每个Object都可接受和处理信号,而信号是从属于某个线程的,因此QObject也就只能从属于某个线程了。这只是我的粗浅理解,不知道对不对。而且我觉得能不能把QObject的最基本服务提炼出来作为更高一层呢?这样更易于理解,也便于与其它语言交互,还可少用内存和其它负担。目前QObject管的事情实在太多了,强迫QObject从属于某个线程感觉有点怪异。对象交互性是很重要,但从实际角度而言,主要是GUI对象交互管理比较麻烦,所以没有必要将信号槽机制放在根对象级。

QObject还可调用metaObject()返回QMetaObject,里面又包括很多东西(类名,超类名,属性,信号,槽等等,QObject提供的objectName()是实例的名称,不是类名)。每个使用Q_OBJECT宏的子类实例,都会包括一个metaObject。但是QMetaObject是通过宏关键字实现的,所以除非官方提供了相应方法,否则无法增加/修改其内容。但是偏偏官方还提供了Q_DECLARE_METATYPE(MyClass)。这样一来,QMetaObject所包含的东西几乎是无限制的,其功能可谓异常强大。

最后,QObject还包括了customEvent,childEvent和timerEvent三个事件,而TObject却没有事件,要等到TControl才有,因为到了TControl才开始真正处理GUI事件。顺便数了一下,QWidget有31个事件(都是些保护函数),其中包括了winEvent函数。

---------------------------------------------------------------------------

让我觉得最有趣的就是,QT也有一个Application,并且相当于也是继承自TComponent。

QCoreApplication 最重要的功能是用来管程序的事件过滤(包括non-GUI的程序),而且QApplication管的事情非常多:

1. main函数的参数都传给它(Delphi则使用ParamStr这个系统级的变量解决了问题)
2. 管理QInputContext,里面包括输入方法和状态
3. Session
4. 显示状况(字体,styleSheet,调色板,光标,文字左右方向)
5. threshold 自动最大化的门槛,警告窗口,焦点变化,关闭closeAllWindows,当前激活的窗口,记录最后关闭的窗口等等
6. 提交数据
7. 与session manager的交互
8. 与外部桌面,键盘,鼠标的交互,双击间隔等等

看了一下Delphi的TApplication,主要还是管程序的运行与终止,以及它所有的子窗口。总的来说,QApplication的功能比TApplication管的事情多的多,因为Delphi还有TScreen分担一小部分功能,既不需要跨平台,且有winapi助阵因而对其它功能不以为然,TApplication把它的子窗口都管理管理好就行啦!虽然程序员也可使用winapi帮助QApplication,但是那样代码就不跨平台啦!因此QApplication被迫设计成多管许多系统方面的闲事。最后还发现application.run与app.exec都是那么的一致,控制GUI线程的事件/消息循环,真是太逗了。

------------------------------------------------------------------------------

那么接下去呢?Delphi单独写了一个TControl,主要目的是给图形类也提供一些鼠标处理的功能和文字字体颜色对齐这些基本的显示功能(比如用户可点击TLabel),这是Delphi非常独特和强大的功能。而QT接下去就是QWidget,相当于把TControl和TWinControl的功能直接合并了,QLabel就是继承自它的,这样一来每个QWidget都有句柄(问题:为啥Spy++探测不到QT程序的每个子元素),有了句柄还不是可以随心所欲的做各种处理,这就和标准Windows控件没有什么区别了。

那么QT的图像显示类怎么处理?基本上是自成一体,查看一下QPaintDevice是原类(不继承自任何类),这时C++的多继承特性就可发挥作用了,QWidget直接继承自QObject和QPaintDevice,即把Delphi的TWinControl和TGraphicControl的功能强行融合在一起(因为多继承的原因,这种融合是轻而易举的),准确的说,是把Delphi的TCustomControl和TGraphic的功能强行融合在一起,并且对图像控件和非图像控件不做区分,即每个QWidget子类都可自绘,而不依赖于系统提供的原生控件的功能与界面。Delphi之所以提供TControl是为了在提供一些功能的同时还能节省系统资源,即图形控件不需要系统句柄。而QWidget看起来没有强行区分图像控件和句柄控件,但它在更底层的实现上,实现了所有控件都是自绘,因此不需要在更上层的类库划分里再次区分两者。这么说来,两者还真是异曲同工呢,只是实现层面不同而已。

再进一步说,无论QT还是Delphi,首先它的是一个GUI元素(有没有句柄则不一定),它才可以具备自绘功能。但是如何自绘,以及哪些功能是通用的,这就需要一个单独的类进行定义,而不可能直接放到QWidget和TGraphicControl里,此时QT的QPaintDevice和Delphi的TGraphic就扮演了这种功能。不同之处在于QPaintDevice是原类,而TGraphic却仍继承了TObject和TPersistent,前面说过了TPersistent的功能,QPaintDevice也有(尽管它是原类),但继承自TObject并获取它提供的功能感觉不是很必要,也许这是Delphi基于RAD的设计的原因——为了管理和使用上的方便,因此才这样规定所有类都必须继承TObject。TGraphic还必须实现TInterface, IStreamPersist两个接口,说明还提供了引用计数和随心所欲的流入流出(TPersistent是针对DFM文件格式的)。

TComponent.Name与QObject.objectName相似(注意,TObject没有Name属性)
TComponent.tag与QWidget::accessibleName和QWidget::accessibleDescription比较相似

最后一个问题,QT为什么没有Delphi里对应的TForm?目前的情况是QMainWindow对应Delphi的主TForm,它继承自QWidget,相当于把控件专门强化后专门用来做主界面。而QT的每一个QWidget,都可作为一个显示窗口(除了主Form以外的每一个TForm),因此不需要单独定义TForm对应的组件,换而言之QWidget提供的功能过于强大,每一个QWidget既可以自己作为窗口,也可作为窗口的一个子元素。

QWidget过于强大,看看这些函数就知道了,大概QT官方是想尽可能的提供最方便的全部界面功能:
setGraphicsEffect
setMask
setStyle
windowModality
setWindowRole
而Delphi尽管也异常强大,但也没有直接提供如此之多的功能,更多的还是要基于Winapi的特性来扩展相应的功能。其实QT这么做也是没有办法呀。Delphi控件在取得Windows句柄后可以有winapi随时来助阵,但QT一切都是自绘,如果它官方不提供这种基本的特殊功能(好像有点绕口),普通程序员是很难进行扩充的。

这里还要提一句,体系结构类的函数多不要紧,那个完全不占内存,只有类里的数据成员才会增加对象的内存大小。

还有QDialog,还有。。。以后再补充。

------------------------------------------------------------------------------

今天又发现,QDesktopWidget相当于TScreen,真是差点笑死:
QDesktopWidget* d = QApplication::desktop();
区别在于QDesktopWidget它没有提供一个全局实例,而是每次都要返回指针。但事实上也是一直存在于内存中。

但是Delphi没有提供QSessionManager,也许是它有winapi,所以不需要吧。

------------------------------------------------------------------------------

还有一个重大的区别,就是Delphi只使用了绝对坐标体系,而QT同时使用了Layout可变的相对坐标体系(其实Delphi最新的FMX体系也提供了类似的layout)和setGeometry绝对坐标体系,还有QSS也能控制一部分界面排版(又跟VCL Style对应上了),这三者可同时起作用,并且相互影响或屏蔽,因此导致我在开发的时候经常产生一些困惑。

------------------------------------------------------------------------------

总的来说,QT的体系结构与Delphi类库体系结构十分相似,没有什么本质区别,但是鉴于Delphi严格区分图像控件和非图像控件,说明管理的更精细一些,把TForm与普通控件区分开也是这个原因,节省系统资源。而Delphi强调TComponent,除了提供父子控件的内存管理功能以外,还方便对非可视的算法与系统功能也可制作控件,也算是它的一大特色。

QT类库与Delphi类库的体系结构对比——两者十分类似!的更多相关文章

  1. QT类库与Delphi VCL类库的体系结构对比——两者十分类似!

    今天在看QT对象内存管理的一篇文章时:http://blog.csdn.net/dbzhang800/article/details/6300025想到了一个问题:就是QT类库体系结构与Delphi类 ...

  2. 两款JSON类库Jackson与JSON-lib的性能对比(新增第三款测试)

    本篇文章主要介绍了"两款JSON类库Jackson与JSON-lib的性能对比(新增第三款测试)",主要涉及到两款JSON类库Jackson与JSON-lib的性能对比(新增第三款 ...

  3. ThinkPHP 3.2公共类库、应用类库ThinkPHP/Library讲解

    一.ThinkPHP的类库主要包括公共类库和应用类库,都是基于命名空间进行定义和扩展的.只要按照规范定义,都可以实现自动加载.        公共类库 公共类库通常是指ThinkPHP/Library ...

  4. C#-概念-基础类库:基础类库

    ylbtech-C#-概念-基础类库:基础类库 基础类库 (BCL) 是微软所提出的一组标准库可提供.NET Framework所有语言使用. 随着 Windows 以及 .NET Framework ...

  5. [原创][开源]SunnyUI.Net, C# .Net WinForm开源控件库、工具类库、扩展类库、多页面开发框架

    SunnyUI.Net, 基于 C# .Net WinForm 开源控件库.工具类库.扩展类库.多页面开发框架 Blog: https://www.cnblogs.com/yhuse Gitee: h ...

  6. C++CLR类库封装Native类库并用C#调用 - 草稿

    1.创建Native类库 新建项目->其他语言->Visual C++->Win32控制台应用程序->DLL     添加头文件       添加源文件       选择生成路 ...

  7. delphi TEdit设为下横线,类似填表格

    delphi TEdit设为下横线,类似填表格效果,无需第三方控件就可以实现. 无须编写代码,只要设置一下控件属性 需要修改这些属性: BorderStyle改为bsNone BevelKind改为b ...

  8. qt基础知识之类库概述

    qt是用标准c++编写的跨平台开发类库,它对标准c++进行拓展,引入元对象系统.信号&槽.属性等特征 全局定义 容器类及对应迭代器 qt的模块化体系,分为 基本模块和拓展模块,一个模块通常就是 ...

  9. Delphi 类库(DLL)动态调用与静态调用示例讲解

    在Delphi或者其它程序中我们经常需要调用别人写好的DLL类库,下面直接上示例代码演示如何进行动态和静态的调用方法: { ************************************** ...

随机推荐

  1. C#泛型集合—Dictionary<K,V>使用技巧

    转载:http://blog.csdn.net/a125138/article/details/7742022 1.要使用Dictionary集合,需要导入C#泛型命名空间 System.Collec ...

  2. 安卓数据存储(3):SQLite数据库存储

    SQLite简介 Google为Andriod的较大的数据处理提供了SQLite,他在数据存储.管理.维护等各方面都相当出色,功能也非常的强大.SQLite具备下列特点: 1.轻量级:使用 SQLit ...

  3. <转载>解决div里面img的缝隙问题

    转载自:http://blog.sina.com.cn/s/blog_9fd5b6df01013mld.html   练习切图时发现img和父级div之间总是有2px空隙(chrome),上网搜索解决 ...

  4. CSS 隐藏多余的字符

    日常开发中常常会碰到,字符长度太大,撑破了样式的问题.如果采用截取的话,显然是不灵活的.但是通过css样式来控制显示就比较简单和高效了.下面是关键代码 样式名称{wedth:??px;height=? ...

  5. 关于利用动态代理手写数据库连接池的异常 java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.sql.Connection

    代码如下: final Connection conn=pool.remove(0); //利用动态代理改造close方法 Connection proxy= (Connection) Proxy.n ...

  6. dbforge studio for mysql 怎样破解

    下载好dbforge studio压缩包有两个exe,dbforge.studio.for.mysql.6.0.315-loader.exe ,和dbforgemysql.exe,安装后目录在C:\P ...

  7. C语言之指针1.1数组

    void main() { ]={,,,,,}; ;i++) { printf("%d\n",*(arr+i)); } } 输出结果时候123456

  8. UITextField文本字段控件的位置

    如果需要更改默认的UITextField清除按钮.左右视图等等控件的位置,可以通过如下设置: // 控制清除按钮的位置 (默认 width = 15 = height) -(CGRect)clearB ...

  9. 对REST的一些理解

    昨天学习REST,发现有篇文章写的真心不错,看了一遍,并没有完全理解,将一些感觉比较重要的做个记录.  文章链接:REST简介 定义 Representational State Transfer ( ...

  10. 第4章 管道与FIFO

    4.1 概述 管道只在亲缘进程间使用,FIFO在任意进程间使用 4.2 管道 #include <unistd.h> ]) fd[0]用来读管道,fd[1]用来写管道 1)命令who |  ...