2010-07-15 65 views
9

我有一個類(MyClass),它從Qt內置對象(QGraphicsTextItem)繼承了其大部分功能。 QGraphicsTextItem間接從QObject繼承。 MyClass也實現了一個接口,MyInterface使用Qt信號和具有多重繼承的插槽

class MyClass : public QGraphicsTextItem, public MyInterface 

我需要能夠在MyInterface*使用connectdisconnect。但看起來connectdisconnect只適用於QObject*實例。由於Qt不支持來自QObject派生類的多重繼承,因此我無法從QObject派生MyInterface。 (無論如何,這對接口來說都沒有什麼意義)。

有一個discussion of the problem online,但是IMO提出的解決方案在通常情況下是無用的(通過接口訪問一個對象),因爲你不能連接信號和插槽從MyInterface*,但必須將其轉換爲派生類型。由於MyClass是許多MyInterface派生類中的一個,因此如果將這種轉換爲這種其他的如果該轉換爲該語句並且破壞了該接口的目的,則這將需要「代碼難聞」。

有沒有很好的解決這個限制?

更新:我注意到,如果我dynamic_cast一個MyInterface*QObject*(因爲我知道所有衍生MyInterface類也從QObject繼承最終,它似乎工作,即:

MyInterface *my_interface_instance = GetInstance(); 
connect(dynamic_cast<QObject*>(my_interface_instance), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot())); 

但這真的好像我要求未定義的行爲....

+0

你是怎麼聲明MyInterfaceSignal的? – 2010-07-16 07:07:22

+0

'MyInterfaceSignal'在'MyInterface'中聲明爲一個*非信號*保護的純虛方法,然後在派生類中作爲*信號*聲明。因此,編譯器確保派生類具有該方法,但是由實現者將其標記爲信號。這很麻煩,因爲我沒有真的從MyInterface.MyInterfaceSignal調用虛擬調用表,而是依賴於SIGNAL宏在一天結束時只是解析爲「 char *'方法名稱。 – 2010-07-16 12:43:08

回答

12

你自己找到了答案:dynamic_cast的工作原理你會期待的。這不是未定義的行爲。如果你得到的MyInterface實例不是QObject,那麼強制轉換將返回null,並且你可以防止它發生(這不會發生,因爲你說接口的所有實例都是QObjects)。但請記住,您需要啓用RTTI才能正常工作。

我也會提供一些其他的建議:

  • 使用Q_INTERFACES功能(它不僅爲插件)。然後,當您真的需要時,您將使用QObject工作並使用qobject_cast查詢MyInterface。我不清楚你的問題,但是因爲你知道所有MyInterface實例都是QObject,所以這似乎是最明智的方法。

  • 將一個QObject* asQObject()抽象方法添加到MyInterface並在所有子類中實現它作爲{ return this; }

  • 具有一個QGraphicsTextItem(組合物),而不是被一個(繼承)。

6

你可以聲明MyInterface ta KES一個QObject的構造函數中:

class MyInterface { 
public: 
       MyInterface(QObject * object); 
    QObject * object() { return m_object; } 
    ... 
private: 
    QObject * m_object; 
}; 

MyInterface::MyInterface(QObject * object) : 
    m_object(object) 
{ 
    ... 
} 
在MyClass的構造

然後:

MyClass::MyClass() : 
MyInterface(this) 
{ 
    ... 
} 

並且可以連接信號:

MyInterface *my_interface_instance = GetInstance(); 
connect(my_interface_instance->object(), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));