原文地址:http://blog.163.com/net_worm/blog/static/1277024192010097430321/
在開始分析之前交代一下,一是分析的QT在Window平台實現(其它OS類似);二、分析的手段為看源碼+單步跟蹤。有時候會讓編譯器產生預編譯后的輸出(使用-E參數),便於觀察;三、分析得QT版本為4.5.3
下面是QT經典的Hello world程序
1 #include <qapplication.h> 2 #include <qpushbutton.h> 3 #include <qfont.h> 4 5 int main( int argc, char **argv ) 6 { 7 QApplication a( argc, argv ); 8 QPushButton quit( "Quit", 0 ); 9 quit.resize( 75, 30 ); 10 quit.setFont( QFont( "Times", 18, QFont::Bold ) ); 11 QObject::connect( &quit, SIGNAL(clicked()), &a, SLOT(quit()) ); 12 quit.show(); 13 return a.exec(); 14 }
第一句聲明了一個QApplication的對象,QApplication的類繼承關系為:
1 QApplication : QCoreApplication : QObject
先觀察QApplication的構造函數:
1 QApplication::QApplication(int &argc, char **argv) 2 : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient)) 3 { Q_D(QApplication); d->construct(); }
這里先后做了三件事:新生成一個QApplicationPrivate對象並傳遞給QCoreApplication;宏Q_D;調用d->construct()。
看Q_D的定義:
1 #define Q_D(Class) Class##Private * const d = d_func()
Q_D(QApplication);展開后是:
1 QApplicationPrivate * const d = d_func();
在附近正好看到Q_Q的定義:
1 #define Q_Q(Class) Class * const q = q_func()
由此看到在QT的程序里最好不要定義d、q這樣的變量。
所以d->construct()調用的其實是
1 QApplicationPrivate::construct();
那么這個construct()干了什么事呢?
1 void QApplicationPrivate::construct() 2 { 3 initResources(); // 初始化資源 4 5 qt_is_gui_used = (qt_appType != QApplication::Tty); 6 process_cmdline(); // 掃描分析命令行參數 7 // Must be called before initialize() 8 qt_init( this, qt_appType ); // 在initialize()之前必須執行的初始化,例如色彩、字體、鍵盤等 9 initialize(); 10 eventDispatcher->startingUp(); 11 12 }
其中eventDispatcher->startingUp();實際調用的是:QEventDispatcherWin32::startingUp(),主要是注冊事件分發器。
回來看QCoreApplication的構造過程,把QApplicationPrivate對象傳遞給QOjbec,然后調用init()。
1 QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p) 2 : QObject(p, 0) 3 { 4 init(); 5 // note: it is the subclasses' job to call 6 // QCoreApplicationPrivate::eventDispatcher->startingUp(); 7 }
我們先來看QCoreApplication::init()干了什么事呢?
1 void QCoreApplication::init() 2 { 3 Q_D(QCoreApplication); 4 5 // Get the application name/instance if qWinMain() was not invoked 6 set_winapp_name(); // 設置應用程序的名字 7 8 Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object"); 9 QCoreApplication::self = this; 10 11 QThread::initialize(); // 初始化線程 12 13 // use the event dispatcher created by the app programmer (if any) 14 if (!QCoreApplicationPrivate::eventDispatcher) 15 QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher; 16 // otherwise we create one 17 if (!QCoreApplicationPrivate::eventDispatcher) 18 d->createEventDispatcher(); // 生成事件分發 19 Q_ASSERT(QCoreApplicationPrivate::eventDispatcher != 0); 20 21 if (!QCoreApplicationPrivate::eventDispatcher->parent()) 22 QCoreApplicationPrivate::eventDispatcher->moveToThread(d->threadData->thread); 23 24 d->threadData->eventDispatcher = QCoreApplicationPrivate::eventDispatcher; 25 26 if (!coreappdata()->app_libpaths) { 27 // make sure that library paths is initialized 28 libraryPaths(); // 確認或設定DLL庫的路徑 29 } else { 30 d->appendApplicationPathToLibraryPaths(); 31 } 32 33 qt_startup_hook(); // 目前是空函數 34 }
Object的構造又做了什么事情呢?
QObject::QObject(QObjectPrivate &dd, QObject *parent) : d_ptr(&dd) 將QApplicationPrivate對象傳遞給d_ptr,這個d_ptr是什么呢?
我們看QObject的類定義,d_ptr是QObject中唯一的數據成員:
protected: QObjectData *d_ptr; 至此,QApplication對象的初始基本分析完畢,除了很多初始化的動作之外,主要就是把QApplication和QApplicationPrivate關聯起來
