使用具有多重继承的 Qt 信号和槽

Posted

技术标签:

【中文标题】使用具有多重继承的 Qt 信号和槽【英文标题】:Using Qt signals and slots with multiple inheritance 【发布时间】:2010-07-15 20:25:07 【问题描述】:

我有一个类 (MyClass),它从 Qt 内置对象 (QGraphicsTextItem) 继承了它的大部分功能。 QGraphicsTextItem 间接继承自 QObjectMyClass 也实现了一个接口,MyInterface

class MyClass : public QGraphicsTextItem, public MyInterface

我需要能够在MyInterface* 上使用connectdisconnect。但似乎connectdisconnect 仅适用于QObject* 实例。由于 Qt 不支持从 QObject 派生类进行多重继承,因此我无法从 QObject 派生 MyInterface。 (无论如何,这对于界面来说也没有多大意义。)

有一个discussion of the problem online,但 IMO 建议的解决方案在常见情况下(通过其接口访问对象)相当无用,因为您无法连接来自 MyInterface* 的信号和插槽,但必须将其转换为派生-类型。由于MyClass 是许多MyInterface 派生类之一,这将需要“代码异味” if-this-cast-to-this-else-if-that-c​​ast-to-that 语句并违背了界面。

这个限制有什么好的解决办法吗?

更新:我注意到如果我将dynamic_cast 一个MyInterface* 转换为QObject*(因为我知道所有MyInterface 派生类最终也继承自QObject,好像可以了。就是:

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

但是这真的似乎我在要求未定义的行为....

【问题讨论】:

您如何以及在何处声明 MyInterfaceSignal? MyInterfaceSignalMyInterface 中被声明为一个非信号受保护的纯虚方法,然后在派生类中作为一个信号。因此,编译器确保派生类具有该方法,但由实现者将其标记为信号。这很糟糕,因为我不是真的MyInterface.MyInterfaceSignal 调用虚拟调用表,而是依赖于SIGNAL 宏在一天结束时只是解决的事实到 char* 方法名称。 【参考方案1】:

您自己找到了答案:dynamic_cast 按您的预期工作。这不是未定义的行为。如果您获得的 MyInterface 实例不是 QObject,则强制转换将返回 null 并且您可以防范这种情况(这不会发生,因为您说接口的所有实例也是 QObjects)。但是请记住,您需要打开 RTTI 才能使其工作。

我还会提供一些其他建议:

使用 Q_INTERFACES 功能(不仅适用于插件)。然后,您将根据 QObject 工作,并在真正需要时使用 qobject_cast 查询 MyInterface。我不详细了解您的问题,但是既然您知道所有 MyInterface 实例也是 QObjects,这似乎是最明智的做法。

在 MyInterface 中添加一个 QObject* asQObject() 抽象方法,并在所有子类中将其实现为 return this;

拥有一个 QGraphicsTextItem(组合)而不是存在一个(继承)。

【讨论】:

【参考方案2】:

您可以在其构造函数中声明采用 QObject 的 MyInterface:

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()));

【讨论】:

以上是关于使用具有多重继承的 Qt 信号和槽的主要内容,如果未能解决你的问题,请参考以下文章

Qt 多重继承和信号

QObject 多重继承

Qt中图元对象的多重集成

来自两个抽象类的多重继承 (Qt)

Qt中的多重继承

Qt、多重继承、包装器或事件过滤器