2010-07-15 7 views
9

Ho una classe (MyClass) che eredita gran parte delle sue funzionalità da un oggetto incorporato Qt (QGraphicsTextItem). QGraphicsTextItem eredita indirettamente da QObject. MyClass implementa anche un'interfaccia, MyInterface.Utilizzo di segnali Qt e slot con ereditarietà multipla

class MyClass : public QGraphicsTextItem, public MyInterface 

ho bisogno di essere in grado di utilizzare connect e disconnect su MyInterface*. Ma sembra che connect e disconnect funzionino solo su istanze QObject*. Poiché Qt non supporta l'ereditarietà multipla dalle classi derivate da QObject, non è possibile derivare MyInterface da QObject. (Né sarebbe comunque molto sensato per un'interfaccia.)

C'è un discussion of the problem online, ma IMO la soluzione proposta è abbastanza inutile nel caso comune (accedere a un oggetto tramite la sua interfaccia), perché non è possibile collegare i segnali e slot da MyInterface* ma devono trasmetterlo al tipo derivato. Dal momento che MyClass è una delle molte classi precedute da MyInterface, questo richiederebbe istruzioni "casuali-se-quelle-cast-to-this-cast-to-this-else-if-that-cast-to-that" e vanificherebbe lo scopo dell'interfaccia.

C'è una buona soluzione a questa limitazione?

UPDATE: mi accorsi che se mi dynamic_cast un MyInterface*-QObject* (perché so tutte le classi MyInterface -derived anche ereditare eventualmente da QObject, sembra funzionare Cioè:.

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

Ma questo veramente sembra come se stessi chiedendo un comportamento non definito ....

+0

Come e dove ha dichiarato MyInterfaceSignal? –

+0

'MyInterfaceSignal' è dichiarato come metodo virtuale puro protetto * non-segnale * in' MyInterface', e quindi come un * segnale * nelle classi derivate. Pertanto, il compilatore assicura che le classi derivate abbiano il metodo, ma spetta all'implementatore contrassegnarlo come un segnale. È inutile, perché non sto * * * richiamando la tabella delle chiamate virtuali da 'MyInterface.MyInterfaceSignal', ma piuttosto facendo affidamento sul fatto che la macro SIGNAL è - alla fine della giornata - solo la risoluzione di un' char * 'nome del metodo. –

risposta

12

Ti sei trovato la risposta Il dynamic_cast funziona come ti aspetteresti. Non è un comportamento indefinito. Se l'istanza di MyInterface che hai ottenuto non è un QObject, il cast restituirà null e potrai proteggerti da quello (cosa che non succederà, dal momento che hai detto che tutte le istanze dell'interfaccia sono anche QObjects). Ricorda, tuttavia, che hai bisogno che RTTI sia attivato per farlo funzionare.

Vorrei anche offrire alcuni altri suggerimenti:

  • Utilizzare il Q_INTERFACES funzione (non è solo per i plug-in). Quindi dovresti lavorare in termini di QObject e query per MyInterface usando qobject_cast quando è veramente necessario. Non conosco il tuo problema in dettaglio, ma dal momento che sai che tutte le istanze di MyInterface sono anche QObjects, questo sembra essere l'approccio più ragionevole.

  • Aggiungere un metodo QObject* asQObject() astratto a MyInterface e implementarlo come { return this; } in tutte le sottoclassi.

  • Avere un QGraphicsTextItem (composizione) invece di essere uno (ereditarietà).

6

Puoi dichiarare MyInterface che ta KES un QObject nel suo costruttore:

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

MyInterface::MyInterface(QObject * object) : 
    m_object(object) 
{ 
    ... 
} 

Poi nel MyClass costruttore:

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

E si può collegare il segnale:

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