QObject多重继承

51

我正在尝试使用C++/Qt的混入类(mix in classes)来为一整组小部件提供共同的接口。该接口被定义为基类,如果其他小部件类将其定义为基类,则这些小部件本身将具有那些信号:

class SignalInterface: public QObject {
    Q_OBJECT

    public:
    SignalInterface();
    virtual ~SignalInterface();

    signals:
    void iconChanged(QIcon);
    void titleChanged(QString);
}

class Widget1: public SignalInterface, QWidget{

    public:
    Widget1()
    virtual ~Widget1()

    // The Widget Should Inherit the signals
}

查看类层次结构后,问题显而易见,我遇到了多重继承中的恐怖菱形问题,在这种情况下,Widget1继承自QWidgetSignalInterface,而这两个类都继承自QObject。这会引起任何问题吗?

我们知道,如果QObject类是纯虚的(但实际并非如此),则可以轻松解决此问题。

一种可能的解决方案是:

class Interface: public QWidget {
Q_OBJECT

signals:
void IconChanged(QIcon);
void titleChanged(QString);
}

class Widget1: public Interface {

}

问题在于我已经有很多从QWidget继承的代码了,现在修改起来很麻烦。是否有其他方法?


请查看:https://dev59.com/HGMm5IYBdhLWcg3wBrXD#17943699 - Dmitry Sazonov
1
我遇到了这个问题,只需将信号发射器添加为基接口的成员而不是其基类。 - Zeks
3个回答

61

很不幸,在moc中继承两次QObject会导致问题。

来自http://qt-project.org

 

如果您使用多重继承,moc假定第一个继承的类是的子类。此外,请确保只有第一个继承的类是QObject

我建议使用更像委托模式的东西,或者重新创建具有HasA而不是IsA关系的对象。


1
请注意,对于Qt5,此规则仍然适用:https://doc.qt.io/qt-5/moc.html#multiple-inheritance-requires-qobject-to-be-first(您提供了一个指向Qt4文档的链接) - Tomeg
(当这个问题被提出和回答时,Qt5还不存在) - szatmary

10

如果基类从QObject继承私有,Qt允许多重继承。

例子:

class Base: private QObject {
   Q_OBJECT
   /*Can use signals and slots like any other QObject-derived class*/
};

class Derived1: public Base {
   /*Cannot use signals/slots because it does not "see" that Base inherits from QObject*/
};

class Derived2: public QWidget, public Base {
   Q_OBJECT
   /*Can use signals/slots plus has all the functionality of QWidget and Base*/
};
当然,私有继承是一种完全不同的方法,也许不能给你真正需要的解决方案。我使用它的情况是当我可以只在基类中使用信号/插槽时。当我真正需要在派生类中使用QObject行为时,我会专门从QObject继承来实现这个类。

6
使用Qt5.9编译时,该解决方案在编译moc生成的文件时出现错误: 'static_cast':将'QObject *'转换为'myClass *'存在歧义。 - Esppat
可能是一种不被支持的技术在某些版本/配置的qt中起作用。请查看文档获取官方答案。 - wheredidthatnamecomefrom
Qt 6.5的表现不佳。 - ניר

3
为什么要使用继承而不是组合?以it技术为例,您可以按照以下方式重写您的代码:
class IMyWidgetSignals : public QObject
{
    Q_OBJECT
signals:
    void iconChanged(QIcon);
    void titleChanged(QString);
};

//------------------------------------------------------------------------------

class IMyWidget {
public:
    IMyWidget () {}
    // virtual functions:
    // ...
    
    IMyWidgetSignals _signals;
};


//------------------------------------------------------------------------------

class Widget1: public QWidget, public IMyWidget
{
public:
    using QWidget::QWidget;
}
//------------------------------------------------------------------------------

int main(...)
{
    
    Widget1 w1;
    w1.show();

    QObject::connect(&w1._signals, &IMyWidgetSignals::iconChanged, [] (const auto &icon) { 
        // ... do smth with icon
    });
}

顺便提一下,KDAB开发人员提出了一种全新的信号/槽/属性机制,不需要任何QObject相关的东西,可能是一个解决方案。https://www.kdab.com/signals-slots-properties-bindings/ - Alex Nevskiy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接