我有一个等级:
class ICommand
{
public:
virtual void start() = 0;
};
class IExtendedCommand : public ICommand
{
public:
virtual void doSomethingElse() = 0;
};
class ConcreteCommand : public ICommand
{
public:
virtual void start() {};
}
class ExtendedConcreteCommand : public ConcreteCommand, public IExtendedCommand
{
public:
virtual void doSomethingElse() {};
}
ICommand和IExtendedCommand对象由工厂创建。
由于某种原因,当编译器说所有ICommand的方法在ExtendedConcreteCommand中都是纯粹的......
任何想法为什么以及如何解决这个问题?
PS:是的我正在将我的Android应用移植到C ++ / Qt(我已经使用了3年)。 无论如何,我想听听你将如何应对这一点。
修改
我正在移植的是MPC和VLC的远程控制应用程序。 我们的想法是创建可以通过工厂发送给玩家的命令。 Factory返回指向实现ICommand的对象的指针。因此,通过切换工厂实现,可以创建不同的命令。 ICommand声明所有主要方法和信号。 IExtendedCommand在玩家之间添加了一些通用信息。所以我想做的是通过工厂实例化IExtendedCommand,设置一些属性然后用start()方法启动它。我还想重用ConcreteCommand的功能。这导致我描述的问题。
答案 0 :(得分:3)
你没有钻石。你有这个:
+----------------------------------- missing start() !
V
pv start() pv doSomethingElse() concrete doSomethingElse()
ICommand ---> IExtendedCommand ---\
> ExtendedConcreteCommand
ICommand ---> ConcreteCommand ---/
pv start() concrete start()
这意味着你有两个类型ICommand
的基类,你需要覆盖它们的纯方法。但只有ConcreteCommand
会覆盖start
的“底部”版本,而另一个版本仍未覆盖。
如果你想要一个真正的钻石,你需要使用虚拟继承ICommand
来制作class IExtendedCommand : virtual public ICommand
基类虚拟,同样也需要ConcreteCommand
。或者,您可以在start
中为ExtendedConcreteCommand
提供另一个覆盖。
答案 1 :(得分:1)
如果我理解你的符号,ExtendedConcreteCommand
应该是一个具体的类,这意味着你试图做的某个地方
ExtendedConcreteCommand command;
在您上传的代码中,ExtendedConcreteCommand
是纯虚拟类,因为方法IExtendedCommand::start()
是纯虚拟的。
实际上,钻石继承是不良的编码实践,应该避免 。如果您坚持这样做,为了避免编译器问题,您必须定义IExtendedCommand::start()
。通过将您的班级修改为
class IExtendedCommand : public ICommand
{
public:
virtual void doSomethingElse() = 0;
virtual void start() {};
};
你的代码编译。
您还可以使用virtual
继承。在这种情况下,您将只有 ICommand
的一个实例,以及一个真正的钻石。在您的示例中,您有两个 ICommand
个实例:一个来自IExtendedCommand
而另一个来自ConcreteCommand
。
答案 2 :(得分:0)
只需从界面继承virtual
。
确实有运行时成本。