对于学校项目,我们必须制作一个“游戏”,在这个游戏中,我们将迷宫可视化并找到解决方法。这种可视化必须以两种不同的方式来实现,在我们的例子中,是基于文本的可视化,并且是一种更理想的方式。
为此,我们必须使用Qt,我们使用的是带有QWidget的QMainWindow,该控件将是一个或另一个可视化对象。看到在游戏中我们应该能够在可视化之间进行切换,我们使用了策略模式,因此制作了一个界面(ViewInterface),并且两个可视化都实现了这一点。除了实现ViewInterface之外,这两种可视化都继承了另一个类,在基于文本的版本中,这是QPlainTextEdit(具有带文本的QWidget),在Fancy中,这是QDialog。这里的问题是,在我的控制器中,我有一个指向ViewInterface的指针,该指针用于填充QWidet,但要执行此操作,ViewInterface也必须继承自QWidget,这会导致此错误:QObject是“ TerminalView”的模棱两可的基础。
由于可以在玩游戏时在视图之间进行切换,并且只能在当前活动的视图上调用更新,因此我们无法将特定的视图传递给“ setWidget”。
我是在做错什么还是该如何解决? (我已经考虑过了,但是无法提供解决方案)。
最佳答案
这里的问题是您继承了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
中的方法,信号和插槽的代理。那不是一个奇妙的解决方案,但是我看不出有其他方法可以解决ViewInterface
和QWidget
之间的“是”关系的钻石问题。