对于学校项目,我们必须制作一个“游戏”,在这个游戏中,我们将迷宫可视化并找到解决方法。这种可视化必须以两种不同的方式来实现,在我们的例子中,是基于文本的可视化,并且是一种更理想的方式。

为此,我们必须使用Qt,我们使用的是带有QWidget的QMainWindow,该控件将是一个或另一个可视化对象。看到在游戏中我们应该能够在可视化之间进行切换,我们使用了策略模式,因此制作了一个界面(ViewInterface),并且两个可视化都实现了这一点。除了实现ViewInterface之外,这两种可视化都继承了另一个类,在基于文本的版本中,这是QPlainTextEdit(具有带文本的QWidget),在Fancy中,这是QDialog。这里的问题是,在我的控制器中,我有一个指向ViewInterface的指针,该指针用于填充QWidet,但要执行此操作,ViewInterface也必须继承自QWidget,这会导致此错误:QObject是“ TerminalView”的模棱两可的基础。

由于可以在玩游戏时在视图之间进行切换,并且只能在当前活动的视图上调用更新,因此我们无法将特定的视图传递给“ setWidget”。


c++ - 策略模式Qt模棱两可的基础-LMLPHP

我是在做错什么还是该如何解决? (我已经考虑过了,但是无法提供解决方案)。

最佳答案

这里的问题是您继承了QObject两次:首先在ViewInterface层次结构中,其次在QDialog层次结构(diamond problem)中。尝试对您的FancyView和TextView类使用虚拟继承(不起作用,因为应该在整个层次结构中使用虚拟继承)

但是您的设计还有另一个问题:QDialog和QPlainTextEdit都继承QWidget。要解决此问题,您可以执行以下操作:


使ViewInterface抽象而不继承QObject。这个抽象类将定义FancyView和TextView的接口,并且可能会或可能不会实现某些通用逻辑。
从QDialog和ViewInterface以及分别从QPlainTextEdit和ViewInterface继承多个继承来实现FancyView和TextView。


这样,您可能不会在模棱两可的基类上遇到任何问题。

更新:


  尚未看到您的修改:确实可以解决问题,但是
  另一个问题出现了:如果我这样做,我将无法使用ViewInterface
  设置我的QWidget的指针。确实有可能,但我认为
  这不是很干净


好吧,这是一个真正的问题。一个明显的解决方案是不使用ViewInterface*代替QWidget*。但这意味着您需要更改很多代码,而对于您的情况而言,实际上可能并不是那么好。

关于给定的评论,我提出另一种解决方案:


ViewInterface继承QWidget(具有所有所需的接口函数):

class ViewInterface: public QWidget {
    Q_OBJECT
    ...
}

ViewInterface构造函数中,设置要由小部件使用的布局并进行设置:

ViewInterface::ViewInterface (QWidget* i_parent)
    : QWidget (i_parent) {
    auto layout {new QGridLayout (this)};

    // Zeroed margins to make full fit.
    layout->setContentsMargins (0, 0, 0, 0);

    setLayout (layout);
}

在派生类的构造函数中,将特定的小部件添加到布局中:

class FancyView : public ViewInterface {
    Q_OBJECT

    FancyView (QWidget* i_parent)
        : ViewInterface (i_parent)
        , dialog_widget_ {new QDialog (this)} {
        layout->addWidget (dialog_widget_);
    }
    ...

private:
    QDialog* dialog_widget_;
}

使用目标小部件实现所需的界面。如果要处理事件,则可以使用QObject::eventFilter ()。在这种情况下,您应该将上面代码中的FancyView对象设置为dialog_widget_的事件过滤器。


注意:在这种情况下,您不能将FancyView用作QDialog。解决此问题的方法是代理QDialog信号,插槽和公共功能,并创建另一个包装类FancyViewDialog,该包装类用作FancyView中的方法,信号和插槽的代理。那不是一个奇妙的解决方案,但是我看不出有其他方法可以解决ViewInterfaceQWidget之间的“是”关系的钻石问题。

10-06 03:17