继续构造函数之旅
结束了忙碌的一天,可以静下心来看看期待已久的Qt源码了。今天的起点是QObject的构造函数。
Q_INVOKABLE explicit QObject(QObject *parent=0);
构造函数的声明是这样的,首先看到的是宏定义:Q_INVOKABLE,该宏在Qt文档中有说明,用于将函数在元对象系统中注册。Explicit关键字,该关键字可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。
接下来是实现的函数头:
QObject::QObject(QObject *parent)
: d_ptr(new QObjectPrivate)
可以看出来,该类创建了QObjectPrivate的对象,这样使得经常修改的内部操作与标准接口分离,同时还为QObject类做了减肥。
Q_D(QObject);
qt_addObject(d_ptr->q_ptr = this);
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
d->threadData->ref();
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
parent = 0;
setParent(parent);
首先看到的是Q_D宏,该宏的实现是这样的:
#define Q_D(Class) Class##Private * const d = d_func()
传入参数是QObject,将宏展开后得到:
QObjectPrivate * const d = d_func();
这里的d_func()有几种不同的实现:
#define Q_DECLARE_PRIVATE(Class) /
inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(d_ptr); } /
inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(d_ptr); } /
friend class Class##Private;
#define Q_DECLARE_PRIVATE_D(Dptr, Class) /
inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } /
inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); } /
friend class Class##Private;
暂时还不清楚到底是哪个,继续往下看了。
qt_addObject(d_ptr->q_ptr = this);
这个函数中,首先是d_ptr->q_ptr = this,该方法将当前对象的指针赋值给了刚刚创建的QObjectPrivate类中的指针。接下来看这个函数:
qt_addObject()
没有找到具体的函数实现,只是发现了采用C函数的声明。
extern "C" Q_CORE_EXPORT void qt_addObject(QObject *)
接下来的做法是获取线程ID了
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
d->threadData->ref();
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
parent = 0;
详细实现在分析QThreadData时再做了解。
setParent(parent);
这句话设置父对象的指针,为了方便引用。开始感觉到,Qt的实现机制中,对灵活性的追求要胜于对速度的追求。
接下来的构造函数是QCoreApplication类的了,终于要接触到最后两个构造函数了。
简单看下文档说明,QCoreApplication类提供了一个事件循环,用于提供对控制台Qt应用程序的支持。
这个类采用了无GUI的事件循环,所有的操作系统事件都将进入到主循环当中。负责对其他来源的处理,并派遣。同时该类负责了对象的初始化以及结束。程序的时间循环在调用exec()函数时开始。长时间的操作可以通过调用processEvents()来保证应用程序的响应。
做了下测试,在一个死循环中调用了该函数,发现程序又可以正常响应了。
得到另外一个说明是:exit()函数需要在所有事件循环退出后才会返回。
言归正传,现在看其构造函数,发现构造了对象QObject(p, 0),之后调用了init函数。看到一个标记,说子类需要调用QCoreApplicationPrivate::eventDispatcher->startingUp();
函数。现在还不清楚是什么含义。
跟踪到init()函数,发现这里做的事情还真不少。
Q_D(QCoreApplication);
首先创建了QCoreApplicationPrivate的一个指针。下面是针对不同平台的一些定义。
在Windows平台下,调用了set_winapp_name()函数。又是一个外部定义的函数,暂时找不到实现,所以不能继续了。但是看到一个提示,当qWinMain()函数无效的时候,用于获取应用程序名称和实例。
再往下是Q_ASSERT_X宏定义,该宏定义用于打印断言信息。
ASSERT failure in divide: "division by zero", file mainwindow.cpp, line 19。
好了,只能到这里了,电池没电了……只能明天继续了,看了构造函数就够我研究好几天的了。
2009年10月14日星期三 00:04