为 Qt 解决这个特定的 C++ 菱形问题 类

Solving this specific C++ diamond problem for Qt classes

我正在使用 QT 的 QQuickFramebufferObject class,它继承自 Qt 库中的 QQuickItem

我有以下用户定义的 class:

class OpenGlBufferItem: public QQuickFramebufferObject

我需要我的 OpenGlBufferItem class 也来自 ReactItem。问题是 ReactItem 最终也是从 QQuickItem 派生的:

class ReactItem : public QQuickPaintedItem

因为QQuickPaintedItem继承自QQuickItem

所以我们有以下问题:

           QQuickItem
          /          \
         /            \
QQuickPaintedItem QQuickFramebufferObject
       /                \
   ReactItem        OpenGlBufferItem

我需要的是

           QQuickItem
          /          \
         /            \
QQuickPaintedItem QQuickFramebufferObject
       /                \
   ReactItem            /
       \               /
        \             /
        OpenGlBufferItem

通常,要解决菱形问题,我们只需声明一些 classes 实际上是从其他 es 继承的。但是,我无法声明 classes RectItemQQuickPaintedItemQQuickFrameBufferObject,因为它们已经给出了。

我该如何进行?

更新:

如果我只是尝试去做

class OpenGlBufferItem: public QQuickFramebufferObject, public ReactItem

我遇到了这些错误:

Command failed: ./build.sh -e "modules/mediaplayer/desktop"
In file included from /home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/EWIEGA46WW/moc_OpenGlBufferQtQuick.cpp:9:0,
                 from /home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/mocs_compilation.cpp:2:
/home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/EWIEGA46WW/../../../../../../../../OpenGlBufferQtQuick.h: In constructor ‘OpenGlBufferItem::OpenGlBufferItem(QQuickItem*)’:
/home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/EWIEGA46WW/../../../../../../../../OpenGlBufferQtQuick.h:90:13: error: reference to ‘connect’ is ambiguous
             connect(parent, SIGNAL(widthChanged()), this, SLOT(parentWidthChanged()));
             ^~~~~~~
In file included from /home/lz/Qt5.11.2/5.11.2/gcc_64/include/QtCore/QObject:1:0,
                 from /home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/EWIEGA46WW/../../../../../../../../OpenGlBufferQtQuick.h:3,
                 from /home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/EWIEGA46WW/moc_OpenGlBufferQtQuick.cpp:9,
                 from /home/lz/orwell/orwellJS/desktop/modules/mediaplayer/desktop/orwell_subdir/orwell_autogen/mocs_compilation.cpp:2:
/home/lz/Qt5.11.2/5.11.2/gcc_64/include/QtCore/qobject.h:308:13: note: candidates are: template<class Func1, class Func2> static typename std::enable_if<(QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1), QMetaObject::Connection>::type QObject::connect(const typename QtPrivate::FunctionPointer<Func>::Object*, Func1, const QObject*, Func2, Qt::ConnectionType)
             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
             ^~~~~~~
/home/lz/Qt5.11.2/5.11.2/gcc_64/include/QtCore/qobject.h:300:13: note:                 template<class Func1, class Func2> static typename std::enable_if<(QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1), QMetaObject::Connection>::type QObject::connect(const typename QtPrivate::FunctionPointer<Func>::Object*, Func1, Func2)
             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
             ^~~~~~~
/home/lz/Qt5.11.2/5.11.2/gcc_64/include/QtCore/qobject.h:269:13: note:                 template<class Func1, class Func2> static typename std::enable_if<(((int)(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0) && (! QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction)), QMetaObject::Connection>::type QObject::connect(const typename QtPrivate::FunctionPointer<Func>::Object*, Func1, const QObject*, Func2, Qt::ConnectionType)
             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
             ^~~~~~~
/

还有更多

这是不可能的。

我正在考虑使用 CRTP(奇怪的重复模板模式),如果您可以修改其中一个 classes 并且可以处理它的限制,理论上可以使用它。 但这在您的情况下不起作用,因为 ReactItem 不是直接从 QQuickItem 派生的,而是从 QQuickPaintedItem 派生的。

让我们假设情况并非如此:

ReactItem 需要更改为如下所示:

template <class T> class ReactItem : public T {/*...*/};

class 层次结构如下所示:

         QQuickItem
        /           \
       /        QQuickFramebufferObject
      /               \
ReactItem<QQuickItem>  \
                        \
                   ReactItem<QQuickFramebufferObject>
                        /
               OpenGlBufferItem

这种方法的限制是,就类型层次结构而言,两个 ReactItem 实例化是不相关的类型。 这意味着之前引用 ReactItem 的许多代码可能需要更改。

对于函数来说这很容易做到:

void f(ReactItem* item) { item->setVisible(true); }
// becomes
template<class T> void f(ReactItem<T>* item)  { item->setVisible(true); }

对于 std::vector<ReactItem*>.

这样的模板化数据成员来说要复杂得多