QMetaObject类的实现

QMetaObject类的实现

周末就这样过去了,都还没有一点假日的感觉,明天又该6点起床,开始我新的一周了。这个学期过的真快,转眼就是8周的时间,自己收获了很多,但是总觉得时间不够用,需要继续努力了。

今天的主要是分析QMetaObject类的实现,这样来详细的理解Qt信号与槽的机制。

首先找到4.6QMetaObject的定义,比较吃惊的是,这个之前一直被我称为类的东西,其声明居然是一个结构体,虽然在C++中,结构体中已经可以包含函数。但是想不明白为什么这里会用结构体来声明该结构。下面是该结构体的声明:

struct Q_CORE_EXPORT QMetaObject

还是继续往下看吧,也许会有新的发现。下面是一些方面的定义,没有找到头绪,于是转向这些方法的实现文件,在这里,看到了关于该类的一些说明,这里我摘录了一些:

The QMetaObject class contains meta-information about Qt objects.

A single QMetaObject instance is created for each QObject subclass that is used in an application, and this instance stores all the meta-information for the QObject subclass. This object is available as QObject::metaObject().

This class is not normally required for application programming, but it is useful if you write meta-applications, such as scripting engines or GUI builders.

/list

    /o className() returns the name of a class.

    /o superClass() returns the superclass's meta-object.

    /o method() and methodCount() provide information

       about a class's meta-methods (signals, slots and other

       /l{Q_INVOKABLE}{invokable} member functions).

    /o enumerator() and enumeratorCount() and provide information about

       a class's enumerators.

    /o propertyCount() and property() provide information about a

       class's properties.

    /o constructor() and constructorCount() provide information

       about a class's meta-constructors.

    /endlist

这些都是对QMetaObject的一定解释,简单了解一下就好。我们回到元对象编译器为我们生成的文件中来,可以看到,我们所定义的信号都被解释成了一个函数:

void MainWindow::hello()

{

    QMetaObject::activate(this, &staticMetaObject, 0, 0);

}

我们调用emit的时候,实际上就是调用了该函数。后续的槽被调用工作,就是由activate函数完成的了。

这里,我们需要特比关注一下emit这个名字,它起到了什么作用。我们转到它的定义:

#ifndef QT_NO_EMIT

# define emit

#endif

发现它竟然如此简单,这时候,不由得让我猜想,该名称只是一个标识而已,而我们如果单纯的调用hello()这个函数,也能达到相同的效果。于是,我去掉了发送先好前的emit,发现,槽也被成功的调用了。原来, emit这个名字仅仅是一个标识而已。

与此同时,我还看到了下面的定义:

// The following macros are our "extensions" to C++

// They are used, strictly speaking, only by the moc.

 

#ifndef Q_MOC_RUN

# if defined(QT_NO_KEYWORDS)

#  define QT_NO_EMIT

# else

#   define slots

#   define signals protected

# endif

原来Qt的所有signals slots居然什么都不是,经过宏定义替换之后,slots什么都没有了,signals变成了protected.而这两个定义,应该是为了元对象编译器做标识用的。

那么,关于信号与槽的实现,关键的入口点还有两个,一个是connect函数做了些什么,另外一个就是activate函数做了什么。

首先下下connect函数的实现:

inline bool QObject::connect(const QObject *asender, const char *asignal,

                             const char *amember, Qt::ConnectionType atype) const

{ return connect(asender, asignal, this, amember, atype); }

该函数将当前对象的指针传递给标准的实现函数,那么转到真正的实现看一下:

bool QObject::connect(const QObject *sender, const char *signal,

                      const QObject *receiver, const char *method,

                      Qt::ConnectionType type)

在这个定义之前,我看到了一段注释,下面做简要的摘录:

/threadsafe

 

    Creates a connection of the given /a type from the /a signal in

    the /a sender object to the /a method in the /a receiver object.

    Returns true if the connection succeeds; otherwise returns false.

You must use the /c SIGNAL() and /c SLOT() macros when specifying

    the /a signal and the /a method, for example:

 

    /snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 22

 

A signal can also be connected to another signal:

A signal can be connected to many slots and signals. Many signals

    can be connected to one slot.

If a signal is connected to several slots, the slots are activated

    in the same order as the order the connection was made, when the

    signal is emitted.

By default, a signal is emitted for every connection you make;

    two signals are emitted for duplicate connections. You can break

    all of these connections with a single disconnect() call.

    If you pass the Qt::UniqueConnection /a type, the connection will only

    be made if it is not a duplicate. If there is already a duplicate

    (exact same signal to the exact same slot on the same objects),

    the connection will fail and connect will return false

 

The optional /a type parameter describes the type of connection

    to establish. In particular, it determines whether a particular

    signal is delivered to a slot immediately or queued for delivery

    at a later time. If the signal is queued, the parameters must be

    of types that are known to Qt's meta-object system, because Qt

    needs to copy the arguments to store them in an event behind the

    scenes. If you try to use a queued connection and get the error

    message

call qRegisterMetaType() to register the data type before you

    establish the connection.

 

感觉这些东西都是很有用的,可以好好看一下,里面有很多是之前都没有考虑过的细节。接下来,我们看下QObject类中connect函数是如何实现的:

{

const void *cbdata[] = { sender, signal, receiver, method, &type };

if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))

    return true;

}

这里做了一个对信号和槽的判断,这个QInternal之前从来没有见过,本来想看个究竟的,但是今天时间不允许了,只能到这里的。明天继续探索喽!去睡觉了,明天早上还要6点起床呢!

 

20091018日星期日 2354

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值