1.屬性有什麼用?
由于c++類具備封裝特性,不推薦對類成員變量(class variables)進行直接存取。現代編譯器引用屬性(property)的概念,對成員變量進行安全的存取。比如在win平台下 vc7有類似于__property或[property]的支援。Qt由于要實作其跨平台(cross platform),引入一套獨特的屬性系統。其底層是由meta compiling進行支援。
2.格式
Q_PROPERTY(type name
READ getFunction
[WRITE setFunction]
[RESET resetFunction]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool])
* Q_PROPERTY: qt裡定義的宏;
* type name: 即類型名+屬性名,屬性名(name)在QObject的setProperty裡被引用;
* READ: 設定讀取成員變量的函數名,一定要是const,可以傳回void,Qvariant支援的對象,指針,或const的引用。READ是必須的,而write, reset等則是可選的;隻有READ的屬性為隻讀屬性;
* WRITE: 寫成員變量的函數名,傳回值必須是void,可以設定一個參數,這個參數可以是void,QVaraint支援的變量,指針,或const的引用。可選;具備READ和WRITe的屬性是可讀寫屬性。
* DESIGNABLE: 訓示該屬性是否被圖形編輯器(比如designer)使用。預設是TRUE;
* SCRIPTABLE: 訓示是否在script裡使用,Trolltech公司同時有基于Qt的QSA,用于在應用程式的腳本程式設計;預設是TRUE;
* STORED: 訓示是否可被持久化(persistence)。隻有WRITE被設定的時候,STORED才有效。預設是TRUE。
3. 使用
比有一個類,
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass (QString f) {this->f =f;}
~MyClass() {}
//property begin
QString getF() const {return f;}
void setF(QString ff) {f=ff;}
//property end
private:
QString f;
};
這時在public之前定義property
Q_PROPERTY (QString F READ getF WRITE setF)
照慣例,讀取函數往往省略get,即定義了
QString F() const {return f;}
這時,Q_PROPERTY (QString F READ F WRITE setF)
但實際上,讀取、寫、和重置(reset)函數可以是任何名字,比如前面用getF。
在使用時,屬性跟一般的成員函數一樣被使用,比如:
MyClass classA("initial");
QString out=classA.getF();
//out = "initial"
QString t="this is a test";
classA.setF(t);
//classA裡的f現在是"this is a test"
此外,可以通過QObject::setProperty()和property()來使用屬性,比如
MyClass classB("classB");
//這時的f是"classB"
classB.setProperty("F", "this is a test");
//這時調用setF("this is a test"),成員變量f現在是"this is a test"
使用setProperty可能效率比直接調用setF低,但注意到setProperty是基類的成員,是以通過QObject::property/setProperty可以周遊全部派生自QOjbect的類的屬性。比如:
QObject* p = &classA;
p->setProperty("F", "test A");
p=&classB;
p->setProperty("F", "test B");
熟悉多态的朋友,馬上就應該聯想到這種機制的一些優越性。其中奧秘請看多類的相關描述,這裡主要講Qt的屬性,不贅。
QObject::property/setProperty跟QMetaObject::propertyCount(),和QMetaObject::property()結合起來,可以實作動态的函數調用,類似于dotnet裡的reflection機制。
4. 如果property的參數是enum,那麼在定義Q_PROPERTY時,必須先告訴meta system使用的enum,使用宏Q_ENUMS,次序無關,如:
Q_PROPERTY(Priority priority READ priority WRITE setPriority)
Q_ENUMS(Priority)
其中Priority是枚舉類型。
5.一個較為複雜的例子,使用了一個引用輸入屬性的寫函數。請注意,此引用必須為const。
CaliforniaWhiteWine.h
#include <QObject>
class WhiteWine
{};
class CaliforniaWhiteWine :
public QObject
{
Q_OBJECT
Q_PROPERTY(WhiteWine& m_wine READ getWine WRITE setWine)
public:
CaliforniaWhiteWine();
CaliforniaWhiteWine(WhiteWine& wine);
~CaliforniaWhiteWine();
WhiteWine& getWine() const;
void setWine(const WhiteWine& wine)
{
delete m_wine;
*m_wine = wine;
}
protected:
WhiteWine* m_wine;
};
CaliforniaWhiteWine.cpp
#include "./californiawhitewine.h"
CaliforniaWhiteWine::CaliforniaWhiteWine(void)
{
this->m_wine=new WhiteWine();
}
CaliforniaWhiteWine::~CaliforniaWhiteWine(void)
{
delete m_wine;
}
CaliforniaWhiteWine::CaliforniaWhiteWine(WhiteWine& wine)
{
}
WhiteWine& CaliforniaWhiteWine::getWine() const
{
return *m_wine;
}