国产成人精品三级麻豆,色综合天天综合高清网,亚洲精品夜夜夜,国产成人综合在线女婷五月99播放,色婷婷色综合激情国产日韩

當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > moc文件分析

moc文件分析 時(shí)間:2018-09-26      來源:未知

Qt 不是使用“標(biāo)準(zhǔn)的”C++語言編寫,而是對其進(jìn)行了一定程度的擴(kuò)展。我們可以從Qt增加的關(guān)鍵字看出來:signals、slots或emit。但是使用gcc編譯時(shí),編譯器并不認(rèn)識這些非標(biāo)準(zhǔn)c++的關(guān)鍵字,那么就需要Qt自己將擴(kuò)展的關(guān)鍵字處理成標(biāo)準(zhǔn)的C++代碼。Qt在編譯之前會分析源文件,當(dāng)發(fā)現(xiàn)包含了 Q_OBJECT 宏,則會生成另外一個(gè)標(biāo)準(zhǔn)的C++源文件,這個(gè)源文件中包含了 Q_OBJECT 宏的實(shí)現(xiàn)代碼,這個(gè)源文件名字是將原文件名前面加上 moc_ 構(gòu)成,這個(gè)新的文件同樣將進(jìn)入編譯系統(tǒng),終被鏈接到二進(jìn)制代碼中去,此時(shí),Qt將自己增加的擴(kuò)展轉(zhuǎn)換成了標(biāo)準(zhǔn)的C++文件,moc 全稱是 Meta-Object Compiler,也就是“元對象編譯器”。這就是moc文件的由來。

下面我們來分析一下Moc文件:

一 示例代碼如下:

#include

class CTestMoc : public QObject

{

Q_OBJECT

public:

CTestMoc(){}

~CTestMoc(){}

signals:

void Test1();

void Test2(int iTemp);

private slots:

void OnTest1();

void OnTest2(int iTemp);

};

二 Q_OBJECT宏

#define Q_OBJECT \

public: \

Q_OBJECT_CHECK \

static const QMetaObject staticMetaObject; \

virtual const QMetaObject *metaObject() const; \

virtual void *qt_metacast(const char *); \

QT_TR_FUNCTIONS \

virtual int qt_metacall(QMetaObject::Call, int, void **); \

private: \

Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \

struct QPrivateSignal {};

此宏在QObjectdefs.h頭文件中定義

1 Q_OBJECT_CHECK 定義如下:

#define Q_OBJECT_CHECK \

template inline void qt_check_for_QOBJECT_macro(const ThisObject &_q_argument) const \

{ int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i + 1; }

宏展開終會調(diào)用qYouForgotTheQ_OBJECT_Macro這個(gè)內(nèi)聯(lián)函數(shù)。這個(gè)函數(shù)始終返回0,但是很不明白,為什么之后還要添加一句 i=i?,刨根之后,發(fā)現(xiàn)Q_OBJECT_CHECK宏并沒有做什么工作。

inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }

2 static const QMetaObject staticMetaObject 靜態(tài)的元對象,這個(gè)對象在moc文件里會構(gòu)建,在那里就能看到整個(gè)信號&槽的全貌。

3 virtual const QMetaObject *metaObject() const; 返回一個(gè)元對象。

4 virtual void *qt_metacast(const char *); 元對象中的字符數(shù)據(jù)轉(zhuǎn)換。

5 virtual int qt_metacall(QMetaObject::Call, int, void **); 元對象調(diào)用入口,注意此函數(shù)是public的,槽函數(shù)調(diào)用也是由這個(gè)函數(shù)開始。

6 static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); 由qt_metacall函數(shù)調(diào)用,槽函數(shù)調(diào)用真正處理函數(shù)。Q_DECL_HIDDEN_STATIC_METACALL這個(gè)宏看到后和linux系統(tǒng)有關(guān),其它系統(tǒng)這個(gè)宏是一個(gè)空的宏。

三 Moc文件分析

先說結(jié)論在這里。

1 Qt的信號&槽之間的調(diào)用不是通過指針方式調(diào)用的而是通過索引方式來調(diào)用的.

2 信號也是一個(gè)函數(shù)。

Moc文件有幾個(gè)重要數(shù)據(jù)結(jié)構(gòu),把這幾個(gè)結(jié)構(gòu)之間關(guān)系講清楚大家就清楚Qt的信號槽機(jī)制是如何工作的了。

第一個(gè)結(jié)構(gòu)是 qt_meta_stringdata_CTestMoc_t 定義如下:

struct qt_meta_stringdata_CTestMoc_t {

QByteArrayData data[7];

char stringdata[45];

};

data字段是一個(gè)由byte數(shù)組組成的數(shù)組,數(shù)組大小根據(jù)信號&槽個(gè)數(shù)有關(guān),這個(gè)數(shù)組在調(diào)用QObject的connect函數(shù)時(shí)用來匹配信號名或槽名。

stringdata 存放的是字符資源,存放全部的信號名、槽名、類名。

static const qt_meta_stringdata_CTestMoc_t qt_meta_stringdata_CTestMoc = {

{

QT_MOC_LITERAL(0, 0, 8),

QT_MOC_LITERAL(1, 9, 5),

QT_MOC_LITERAL(2, 15, 0),

QT_MOC_LITERAL(3, 16, 5),

QT_MOC_LITERAL(4, 22, 5),

QT_MOC_LITERAL(5, 28, 7),

QT_MOC_LITERAL(6, 36, 7)

},

"CTestMoc\0Test1\0\0Test2\0iTemp\0OnTest1\0"

"OnTest2\0"

};

qt_meta_stringdata_CTestMoc 這個(gè)就是一個(gè) qt_meta_stringdata_CTestMoc_t結(jié)構(gòu)體的實(shí)例。

QT_MOC_LITERAL(0, 0, 8), 這個(gè)宏生成一個(gè)byte數(shù)組,第一參數(shù)是索引,大家可以看到索引是由 0 - 6 共7個(gè)組成,對應(yīng)的是data字段的長度7,第二個(gè)參數(shù)是在stringdata字段中的開始位置,第三個(gè)參數(shù)是長度。

例如 QT_MOC_LITERAL(0, 0, 8) 索引是0, 開始位置是0, 長度是8,對應(yīng)的字符是"CTestMoc",后面的以此類推。

第二個(gè)結(jié)構(gòu)是 static const uint qt_meta_data_CTestMoc[]

這個(gè)結(jié)構(gòu)體描述的是信號&槽在調(diào)用時(shí)的索引、參數(shù)、返回值等信息。

static const uint qt_meta_data_CTestMoc[] = {

// content:

7, // revision

0, // classname

0, 0, // classinfo

4, 14, // methods

0, 0, // properties

0, 0, // enums/sets

0, 0, // constructors

0, // flags

2, // signalCount

// signals: name, argc, parameters, tag, flags

1, 0, 34, 2, 0x06,

3, 1, 35, 2, 0x06,

// slots: name, argc, parameters, tag, flags

5, 0, 38, 2, 0x08,

6, 1, 39, 2, 0x08,

// signals: parameters

QMetaType::Void,

QMetaType::Void, QMetaType::Int, 4,

// slots: parameters

QMetaType::Void,

QMetaType::Void, QMetaType::Int, 4,

0 // eod

 };

這個(gè)數(shù)組的前14個(gè)uint 描述的是元對象的私有信息,定義在qmetaobject_p.h文件的QMetaObjectPrivate結(jié)構(gòu)體當(dāng)中,QMetaObjectPrivate結(jié)構(gòu)體我們不做深入分析,但是,在這個(gè)結(jié)構(gòu)體中4, 14, // methods這個(gè)信息描述的是信號&槽的個(gè)數(shù)和在表中的偏移量,即14個(gè)uint之后是信息&槽的信息

qt_meta_data_CTestMoc這個(gè)表中我們可以看到每描述一個(gè)信號或槽需要5個(gè)uint

例如,從表的第14個(gè)uint開始描述的信號信息

// signals: name, argc, parameters, tag, flags

1, 0, 34, 2, 0x06,

3, 1, 35, 2, 0x06,

name:對應(yīng)的是qt_meta_stringdata_CTestMoc 索引,例如1 對應(yīng)的是Test1

argc:參數(shù)個(gè)數(shù)

parameters : 參數(shù)的在qt_meta_data_CTestMoc這個(gè)表中的索引位置。

例如 // signals: parameters

QMetaType::Void,

QMetaType::Void, QMetaType::Int, 4,

void 是信號的返回值,QMetaType::Int是參數(shù)類型, 4 是參數(shù)名,在qt_meta_stringdata_CTestMoc中的索引值。

tag:這個(gè)字段的數(shù)值對應(yīng)的是qt_meta_stringdata_CTestMoc 索引,在這個(gè)moc文件里對應(yīng)的是一個(gè)空字符串,具體怎么用,在源代碼里沒看懂。

flags:是一個(gè)特征值,是在 enum MethodFlags 枚舉中定義。

enum MethodFlags {

AccessPrivate = 0x00,

AccessProtected = 0x01,

AccessPublic = 0x02,

AccessMask = 0x03, //mask

MethodMethod = 0x00,

MethodSignal = 0x04,

MethodSlot = 0x08,

MethodConstructor = 0x0c,

MethodTypeMask = 0x0c,

MethodCompatibility = 0x10,

MethodCloned = 0x20,

MethodScriptable = 0x40,

MethodRevisioned = 0x80

};

大家可以看到,槽對應(yīng)的是MethodSlot 0x08, 信號對應(yīng)的是MethodSignal 和AccessPublic 相或。

第三部分 QObject 中靜態(tài)函數(shù) qt_static_metacall 實(shí)現(xiàn)

void CTestMoc::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)

{

if (_c == QMetaObject::InvokeMetaMethod) {

CTestMoc *_t = static_cast(_o);

switch (_id) {

case 0: _t->Test1(); break;

case 1: _t->Test2((*reinterpret_cast< int(*)>(_a[1]))); break;

case 2: _t->OnTest1(); break;

case 3: _t->OnTest2((*reinterpret_cast< int(*)>(_a[1]))); break;

default: ;

}

..........

}

現(xiàn)在看這個(gè)就比較直觀了,qt_metacall方法通過索引調(diào)用其它內(nèi)部方法。Qt動態(tài)機(jī)制不采用指針,而由索引實(shí)現(xiàn)。實(shí)際調(diào)用方法的工作由編譯器實(shí)現(xiàn)。這使得信號和槽的機(jī)制執(zhí)行效率比較高。

參數(shù)由一個(gè)指向指針數(shù)組的指針進(jìn)行傳遞,并在調(diào)用方法時(shí)進(jìn)行適當(dāng)?shù)霓D(zhuǎn)換。當(dāng)然,使用指針是將不同類型的參數(shù)放在一個(gè)數(shù)組的唯一辦法。參數(shù)索引從1開始,因?yàn)?號代表函數(shù)返回值。

第四部分 QObject 中靜態(tài)staticMetaObject的賦值

const QMetaObject CTestMoc::staticMetaObject = {

{ &QObject::staticMetaObject, qt_meta_stringdata_CTestMoc.data,

qt_meta_data_CTestMoc, qt_static_metacall, 0, 0}

};

ok,通過這個(gè)靜態(tài)變量就保存了moc文件的信號&槽的調(diào)用索引信息。在信號&槽綁定的時(shí)候就是通過這些信息一步一步建立的綁定關(guān)系。

第四部分 信號就是函數(shù)。

大家可以Moc文件中看到信號的實(shí)現(xiàn)。

上一篇:Android.mk分析

下一篇:ARM處理器中SWI異常中斷處理程序的實(shí)現(xiàn)

熱點(diǎn)文章推薦
華清學(xué)員就業(yè)榜單
高薪學(xué)員經(jīng)驗(yàn)分享
熱點(diǎn)新聞推薦
前臺專線:010-82525158 企業(yè)培訓(xùn)洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠(yuǎn)見科技集團(tuán)有限公司 版權(quán)所有 ,京ICP備16055225號-5,京公海網(wǎng)安備11010802025203號

回到頂部