标准的C++对象模型,对于对象范例提供了高效率的运行支持,但是它的静态特性在某些问题领域却显得不灵活.图形化用户接口编程是需要运行效率和高水平灵活性的领域.而Qt支持这个,因为它结合了C++的速度和Qt对象模型的灵活性.
那么它又是怎么做到这样的呢?
Qt给C++增加了以下特性:
1.对象间的无缝对接通信:信号与槽机制
2.可查询且可设计的对象属性
3.强大的事件以及事件过滤器
4.字符串的国际化
5.高精度的时间分割驱动,使得在一个GUI的事件驱动做可以优雅地并行多个任务
6.以自然的方式组织可继承且可查询的对象树者对象的拥有权
7.被守护的指针,对象指针会在所指向的对象销毁以后自动重置为0,不像纯C++指针,当对象被销毁了,就成了一个危险指针.
8.动态转换
基于QObject的继承,Qt的很多特性都已经通过标准的C++技术实现,但是,像对象的通信机制以及动态属性系统,则需要Qt自身的元对象编译器(Meta-Object Compiler(moc))所支持的元对象系统.
元对象系统是C++的扩展应用,它可以使得C++这种语言更好地适用于GUI的组件编程. 虽然模板(templates)也能用于C++的扩展,但是这个元对象系统可以让我们得到模板所实现不了的好处.详情可以查看Why Doesn't Qt Use Templates for Signals and Slots?
以下这些类构成了Qt对象模型的基础
(Meta-data)
QMetaClassInfo | 对于一个类的附加信息说明 |
QMetaEnum | 枚举器对应的元数据 |
QMetaMethod | 有关于成员函数的元数据 |
QMetaObject | 对象的元信息 |
QMetaProperty | 关于某一属性的元数据 |
QMetaType | 掌管着元对象系统的类型命名 |
QObject | 所有Qt对象的基础之类 |
QObjectCleanupHandler | 监视着QObject的生命周期 |
QPointer | 提供对QObject的引用的一个模板类 |
QSignalMapper | 为标记过的发送者绑定对象 |
QVariant | 可以转换Qt最常用的数据类型 |
Qt Objects:Identity vs Value
上面所列出的部分特性,是需要我们思考 Qt Objects是作为个体,而不是值, 值是可以用来复制和赋予的,但是个体只能克隆.克隆意味着创建一个新个体,而不是对旧个体的完全复制. 举个例子来说,双胞胎拥有不同的个体标识,他们虽然看起来一样,但是他们有不同的名称,不同的定位,甚至还有完全不同的社交网络.
对一个个体的克隆比对一个值进行复制或者赋值,要复杂的多. 我们可以一起来看看这在Qt的对象模型中意味着什么?
一个Qt对象...
(1)可能有一个独一无二的QObject::objectName().如果我们复制一个Qt对象,那么我们应该给这个副本怎么命名呢?
(2)在对象的继承中有一个位置,如果我们复制一个Qt Object,那么我们应该给这个副本什么位置呢?
(3)能连接到其他对象并向它们发送信号,或者接收它们发出的信号. 如果我们复制一个Qt对象,我们应该怎样将这个连接转 换到副本里?
(4)可以在运行期间动态地添加一个新的属性(C++类中没有声明的属性),如果我们复制一个Qt对象,那么我们是否应该把新添加的属性复制给母体对象呢?
基于以上原因,Qt对象应该被当作一个个体,而不是值(的集合体),个体是可以克隆的,而不是复制或者赋值的,并且克隆一个个体比复制或者赋值要复杂得多.除此之外,QObject对象以及它所有的子类(直接或者间接的)所拥有的复制构造器和赋值构造器都被禁用了。
最后一段话,一开始我并不是很理解,然后分析了以下:
一般来说我们所理解的复制或者赋值就是把一片内存的数据拷贝到另一片内存里,对于简单的基本数据类型来说,这个不会造成混乱,但是QObject以及它们的子类子对象需要支持信号-槽机制,这是一种社交特性,也就是它对应的值是有生气有意义的.如果只是简单地对对象进行复制或者赋值,会造成一个对象有两个爸爸等混乱现象。
但是克隆是比纯粹的复制以及赋值更为复杂的操作,这个复杂性体现在它需要面临并解决上面提出的问题,所以Qt不允许对QObject对象以及它所有的子类对象进行复制和赋值,但允许克隆,至于克隆,对于不同的QObject又有不同的需求不同的情境,所以也没有给出一个标准的克隆案例让大家学习。如果开发人员对于自己操纵的QObject类很有把握,可以自己写一个clone函数。