QT Embedded-----QObject:元对象、signal/slot机制

通常一个类库都会有一个类做为所有类的根类,MFC有CObject,Borland的OWL有TObject,java也有一个object。对于QT Embedded来说,这个类就是QObject。QObject作为根类,定义了整个类库的所需要的一些特性: 元对象模型,signal/slot机制,event机制 等。下面的文章就分别分绍一下。

1.元对象 
  元对象被称做是meta object.在运行时刻(runtime),能够 提供对象的运行时信息

  在C++语言发展的早期,C++语言本身没有定义对象的运行时信息,如输出类的名称,父类的名称,判断对象的继承关系等等。虽然新的C++语言增加了RTTI,但还是不够的。这些信息在面向对象编程和调试程序过程中是非常有用的。因此不同的类库采取了不同的方式来扩展语言。
  MFC的实现方式是宏定义:如DECLARE_DYNAMIC,DECLARE_DYNCREATE,DECLARE_SERIAL。这种实现方式没有扩展语言本身,因此可以不加处理的兼容所有的C++编译器。
  QT的实现方式是 宏定义加moc编译 ,定义宏Q_OBJECT,并对语言本身做了部分扩展,因此需要用QT的moc编译器特殊处理一下,产生一个moc_XXX.cpp的文件,然后就可以使用通用C++编译器编译了。
Q_OBJECT的定义如下:
#define Q_OBJECT /
public: /
  virtual QMetaObject *metaObject() const { /
  return staticMetaObject(); /
  } /
  virtual const char *className() const; /
  virtual void* qt_cast( const char* ); /
  virtual bool qt_invoke( int, QUObject* ); /
  virtual bool qt_emit( int, QUObject* ); /
  QT_PROP_FUNCTIONS /
  static QMetaObject* staticMetaObject(); /
  QObject* qObject() { return (QObject*)this; } /
  QT_TR_FUNCTIONS /
private: /
  static QMetaObject *metaObj;

从定义上看, QT的元对象信息主是通过QMetaObject对象来管理的 ,每一个类都会增加一个
static QMetaObject *metaobj。
QMetaObject 中包含三部分信息:
(1)className,superclassname
  这是用来判断对象的继承关系的,是实现QObject::isA(const char *classname)和QObject::inherits(const char *classname)的基础。
(2)用来实现Q_PROPERTY的property信息。
(3)用来实现signal/slot的信息

2. signal/slot 
   signal/slot机制是QT最具特色的特性。signal/slot巧妙的简单的实现了面向对象编程中经常使用的 观察者模式 (observer,或称为消息预定模式)。同时也封装了callback机制,一定程度上保证了callback函数的类型安全。

从实现上来看,signal/slot需要QMetaObject和moc编译器的支持。signal和slot实际上是两种类函数,分别需要在类函数声明前面加signals和slots两个宏。
以QButton的一个signals和slots为例说明实现过程:
class Q_EXPORT QButton : public QWidget
{
  Q_OBJECT
.........

signals:
  void pressed();   //pressed()函数是由moc编译器实现的,不需要用户实现.

................
public slots:
  void animateClick();


(1)signal/slot机制需要增加Q_OBJECT声明,signal/slot是元对象信息,需要QMetaObject的支持。
(2)signals、slots、emit都是宏,从定义上看,都是空值。对C++编译器编译没有任何影响。实际上,这三个宏都是给QT的moc编译器使用的。 moc编译器会对标记为signals和slots的函数编号,方便的实现(编号,函数名字,函数地址)三者之间的转换 。同时实现了标记为signals的函数。因此pressed()函数的是由moc编译器实现的,不需要用户实现,具体内容在 moc_qbutton.cpp 中。

(3)connect/disconnect
这两个函数的定义如下:
QObject::connect( const QObject *sender, const char *signal, const QObject *receiver, const char *member )
QObject::disconnect( const QObject *sender, const char *signal, const QObject *receiver, const char *member )

QMetaObject中会为每一个signal建立一个 QConnectList 列表, 记录着连接到这个signal的所有receiver和其slot函数。   connect就是在QConnectList中增加一项,让sender的QMetaObject记住。 disconnect的作用相反。
(4)emit pressed()

  emit是一个宏,但是一个空值,因此emit pressed()==pressed()。pressed()是由moc编译器实现的。 QButton::pressed()就是把通过QConnectList把所连接的receiver和其member函数找出来,然后按先后顺序调用receiver->member(),由于是一个list,所以是先连接的slot先执行。这与Observer模式中的实现是一致的。
从上面的分析来看,signal/slot是同步直接调用。实现有些复杂,效率上比callback函数也慢一些,但是对于面向对象编程来说,非常符合对象之间低耦合的思想,减少了对象之间的依赖。使用起来也灵活。函数接口也可以任意组合。的确是QT的特色。

  使用过程中,也需要注意如下几点:
(1)QT的signal和unix操作系统的signal是不同的,unix的signal是进程之间的一种通讯方式,QT的signal是对象之间的一种消息传递方式,不是一个层面的概念。
(2) slot函数的返回值是没有意义的,signal函数是由moc编译器实现的, 从具体实现来看,不关心slot函数的返回值。
(3)根据目前的实现,slot函数的被执行是有顺序的,但是这要依赖于目前的实现,以后或许会变
(4)signal/slot和(public,protected,private)没有冲突,private的函数也可以是signal/slot
(4)slot函数可以是虚函数吗?

(5)signal函数可以是虚函数吗?


原文链接http://blog.chinaunix.net/uid-20808412-id-1832700.html

你可能感兴趣的:(QT Embedded-----QObject:元对象、signal/slot机制)