Qt的元對象系統除了提供信號/槽機制的特性之外,它還提供了以下特性:
| QObject::metaObject() |
返回關聯的元對象 |
| QMetaObject::className() |
在運行時狀態下返回類名 |
| QObject::inherits() |
判斷類的繼承關系 |
| QObject::tr(),QObject::trUtf8() |
提供國際化,翻譯字符串 |
| QObject::setProperty(),QObject::property() |
通過名稱來動態設置和獲取屬性 |
| QMetaObject::newInstance() |
創建新實例 |
通過QObject::metaObject()方法, 所有繼承於QObject的類可以 返回元對象系統為其生成的metaObject對象。QMetaObject提供的一些重要信息:
| QMetaClassInfo |
通過宏Q_CLASSINFO的支持,提供類的附加信息 |
| QMetaEnum |
Qt特色的枚舉對象,支持key和 value之間的互轉 |
| QMetaMethod |
提供類成員函數的元數據 |
| QMetaProperty |
提供類成員屬性的元數據 |
Qt反射前期准備
1、首先得繼承於Q_Object,同時需要在class中加入Q_OBJECT。
2、注冊類成員變量需要使用Q_PROPERTY
Q_PROPERTY( type member READ get WRITE set) 其中READ,WRITE是關鍵字
Type表示成員的類型(不支持自定義類型,對Qt很多基本類型都支持);
Member代表你給該成員另外起的名字,可以和變量名不同;get,set就是自己在C++函數里面定義的基本的訪問函數名,不需要寫參數。
3、注冊類成員函數
如果你希望這個函數能夠被反射,那么很簡單,只需要在類的函數聲明前加入Q_INVOKABLE關鍵字。
下面是一個例子:
//聲明一個繼承於QObject的類
class ReflectionObject : public QObject { Q_OBJECT Q_PROPERTY(int Id READ Id WRITE setId) Q_PROPERTY(QString Name READ Name WRITE setName) Q_PROPERTY(QString Address READ Address WRITE setAddress) Q_PROPERTY(PriorityType Priority READ Priority WRITE setPriority) Q_ENUMS(PriorityType) public: enum PriorityType {High,Low,VeryHigh,VeryLow}; Q_INVOKABLE int Id() {return m_Id; } Q_INVOKABLE QString Name() { return m_Name; } Q_INVOKABLE QString Address() { return m_Address; } Q_INVOKABLE PriorityType Priority() const {return m_Priority; } Q_INVOKABLE void setId(const int & id) {m_Id = id; } Q_INVOKABLE void setName(const QString & name) {m_Name = name; } Q_INVOKABLE void setAddress(const QString & address) {m_Address = address; } Q_INVOKABLE void setPriority(PriorityType priority) {m_Priority = priority; } private: int m_Id; QString m_Name; QString m_Address; PriorityType m_Priority; };
遍歷該類的成員函數:
ReflectionObject theObject; const QMetaObject* theMetaObject =theObject.metaObject(); int methodIndex; int methodCount = theMetaObject->methodCount(); for(methodIndex = 0; methodIndex < methodCount; ++methodIndex) { QMetaMethod oneMethod =theMetaObject->method(methodIndex); qDebug() <<"typeName: " <<oneMethod.typeName(); qDebug() <<"signature: " <<oneMethod.signature(); qDebug() <<"methodType: " <<oneMethod.methodType();; qDebug() <<"parameterNames: " <<oneMethod.parameterNames() <<"\n"; }
其中typeName代表返回類型,signature只的是函數的原貌,methodType代表函數的類型,在Qt中分為三類(槽,信號,普通函數),parameterNames代表函數參數
遍歷該類的成員變量:
int propertyIndex; int propertyCount = theMetaObject->propertyCount(); for(propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex) { QMetaProperty oneProperty =theMetaObject->property(propertyIndex); qDebug() <<"name: " << oneProperty.name(); qDebug() <<"type: " <<oneProperty.type() <<"\n"; }
遍歷該類的枚舉集合:
int enumeratorIndex; int enumeratorCount = theMetaObject->enumeratorCount(); for(enumeratorIndex = 0; enumeratorIndex < enumeratorCount; ++enumeratorIndex) { QMetaEnum oneEnumerator =theMetaObject->enumerator(enumeratorIndex); int enumIndex; int enumCount = oneEnumerator.keyCount(); for(enumIndex = 0;enumIndex < enumCount; ++enumIndex) { qDebug() <<oneEnumerator.key(enumIndex) <<" ==> " <<oneEnumerator.value(enumIndex); } }
這里我們看到QMetaEnum存在key、value配對出現,這必然可以互轉,而QMetaEnum確實提供了方式:valueToKey()、keyToValue()。
反射的應用
反射反射,就我目前的認知水平來看,通過使用字符串,來實現函數的通用化調用,例如你可以利用反射把很多函數放置到數組中,實現一次遍歷,全部調用。
目前見到的大多是利用反射來操作數據庫,例如hibernate,其實可以利用Qt的反射,快速實現所謂的hibernate。
至此,Qt自帶的反射功能已經羅列完整。但是Qt自身並沒有提供類反射機制,就是像Java那樣通過getObject(String)函數,從類型直接構建新的對象。實現類反射機制請閱讀下一篇博客。
http://www.cnblogs.com/RainyBear/p/5251482.html
參考資料:http://blog.csdn.net/playstudy/article/details/7861329;
