c – 虚拟继承纯虚拟(接口)类是一个很好的约定吗?

我经常使用纯虚拟类(接口)来减少当前项目中不同类的实现之间的依赖关系.我甚至拥有层次结构并不罕见,在这些层次结构中我有纯虚拟和非纯虚拟类来扩展其他纯虚拟类.以下是这种情况的一个例子:

class Engine
{ /* Declares pure virtual methods only */ }

class RunnableEngine : public virtual Engine
{ /* Defines some of the methods declared in Engine */ }

class RenderingEngine : public virtual Engine
{ /* Declares additional pure virtual methods only */ }

class SimpleOpenGLRenderingEngine : public RunnableEngine,
    public virtual RenderingEngine
{ /* Defines the methods declared in Engine and RenderingEngine (that are not
     already taken care of by RunnableEngine) */ }

RunnableEngine和RenderingEngine都虚拟地扩展了Engine,因此菱形问题不会影响SimpleOpenGLRenderingEngine.

我想对钻石问题采取预防性的立场,而不是当它成为一个问题时处理它,特别是因为我喜欢编写尽可能容易让别人使用的代码,我不希望他们必须修改我的类,以便他们可以创建特定的类heirarchies,例如如果鲍勃想要这样做:

class BobsRenderingEngine : public virtual RenderingEngine
{ /* Declares additional pure virtual methods only */ }

class BobsOpenGLRenderingEngine : public SimpleOpenGLRenderingEngine,
    public BobsRenderingEngine
{ /* Defines the methods declared in BobsRenderingEngine */ }

如果我没有使SimpleOpenGLRenderingEngine虚拟地扩展RenderingEngine,这是不可能的.我知道Bob想要这样做的概率可能非常低.

因此,我已经开始使用永远扩展纯虚拟类的约定,以便从它们的多重继承不会导致钻石问题.也许这是因为我来自Java并且倾向于仅使用非纯虚拟类的单继承.我确信在某些情况下它可能有点过分但是使用这个约定有什么缺点吗?这会导致性能/功能等问题吗?如果不是,我没有看到不使用该惯例的理由,即使最终可能通常不需要.

最佳答案
我会说,一般来说,鼓励继承是一个坏主意(这就是你通过使用虚拟继承所做的事情).实际上很少有东西能够通过继承隐含的树结构来表示.此外,我发现多重继承倾向于打破单一责任规则.我不知道您的确切用例,我同意有时我们别无选择.

但是在C中我们有另一种组合对象的方法,封装.我发现下面的声明更容易理解和操作:

class SimpleOpenGLRenderingEngine 
{
public:
    RunnableEngine& RunEngine() { return _runner; }
    RenderingEngine& Renderer() { return _renderer; }

    operator RunnableEngine&() { return _runner; }
    operator RenderingEngine&() { return _renderer; }

private:
    RunnableEngine _runner;
    RenderingEngine _renderer;
};

确实,对象将使用比使用虚拟继承更多的内存,但我怀疑复杂的对象是以大量创建的.

现在让我们说你真的想继承一些外部约束.虚拟继承仍然难以操纵:你可能对它感到满意,但是从你的类派生的人可能不会,并且在推导之前可能不会想太多.我想更好的选择是使用私有继承.

class RunnableEngine : private Engine
{
     Engine& GetEngine() { return *this; }
     operator Engine&() { return *this; }
};

// Similar implementation for RenderingEngine

class SimpleOpenGLRenderingEngine : public RunnableEngine, public RenderingEngine
{ };

转载注明原文:c – 虚拟继承纯虚拟(接口)类是一个很好的约定吗? - 代码日志