Usando Qt sinais e slots com herança múltipla
-
16-09-2020 - |
Pergunta
Eu tenho uma classe (MyClass
) que herda a maioria de suas funcionalidades a partir de um Qt incorporado (objetoQGraphicsTextItem
). QGraphicsTextItem
herda-se, indiretamente, a partir de QObject
. MyClass
também implementa uma interface, MyInterface
.
class MyClass : public QGraphicsTextItem, public MyInterface
Eu preciso ser capaz de usar connect
e disconnect
no MyInterface*
.Mas parece que connect
e disconnect
só o trabalho em QObject*
instâncias.Uma vez que o Qt não suporta herança múltipla de QObject classes derivadas, eu não posso derivar MyInterface
a partir de QObject
.(Nem que faça muito sentido para uma interface de qualquer maneira.)
Há um a discussão do problema online, mas IMO a solução proposta é bastante inútil no caso comum (a aceder a um objecto por meio de sua interface), porque você não pode conectar os sinais e slots de MyInterface*
mas deve lançá-lo para a derivada-tipo.Desde MyClass
é um dos muitos MyInterface
classes derivadas, isso necessitaria de "código-fedorento" se-esta-elenco-para-esta-mais-se-o-que-elenco-para-que as declarações e derrota o propósito da interface.
Existe uma boa solução para esta limitação?
ATUALIZAÇÃO: Percebi que se eu dynamic_cast
um MyInterface*
para QObject*
(porque eu sei todos MyInterface
classes derivadas também herdam finalmente, a partir de QObject
, ele parece funcionar.O que é:
MyInterface *my_interface_instance = GetInstance();
connect(dynamic_cast<QObject*>(my_interface_instance), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));
Mas esse realmente parece que eu estou pedindo o comportamento indefinido....
Solução
Você encontrou a resposta a si mesmo:o dynamic_cast funciona como seria de esperar.Ele não é um comportamento indefinido.Se a instância do MyInterface você tem não é um QObject, o elenco retornará nulo e você pode proteger a si mesmo contra o que (o que não vai acontecer, já que você disse que todas as instâncias da interface são também QObjects).Lembre-se, no entanto, que você precisa de RTTI ligado para que ele funcione.
Também gostaria de oferecer algumas sugestões:
Use o Q_INTERFACES funcionalidade (não é só para os plugins).Então você gostaria de trabalhar em termos de QObject e consulta para MyInterface usando qobject_cast quando é realmente necessário.Eu não sei o seu problema em detalhes, mas desde que você saiba que todos os MyInterface instâncias também são QObjects, esta parece ser a abordagem mais sensível.
Adicionar um
QObject* asQObject()
método abstrato para MyInterface e implementá-lo como{ return this; }
em todas as subclasses.Ter um QGraphicsTextItem (composição) em vez de sendo um (herança).
Outras dicas
Você pode declarar MyInterface que leva um QObject em seu construtor:
class MyInterface {
public:
MyInterface(QObject * object);
QObject * object() { return m_object; }
...
private:
QObject * m_object;
};
MyInterface::MyInterface(QObject * object) :
m_object(object)
{
...
}
Em seguida, em MyClass construtor:
MyClass::MyClass() :
MyInterface(this)
{
...
}
E você pode conectar o sinal:
MyInterface *my_interface_instance = GetInstance();
connect(my_interface_instance->object(), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));