虚拟继承和接口

Virtual inheritance and interfaces

本文关键字:接口 继承 虚拟      更新时间:2023-10-16
class IA
{
public:
    virtual void a() = 0;
};
class A: virtual public IA
{
public:
    virtual void a()
    {
    }
};
class IB: virtual public IA
{
public:
    virtual void b() = 0;
};
class B: virtual public IB, public A
{
public:
    virtual void b()
    {
    }
};

您是否总是像我上面一样继承虚拟接口?如果没有,您将如何冲击上述代码?

在分离接口和实现层次结构时,使用多重继承虚拟继承是合适的设计选择。 例如,请参阅:"当虚拟继承是一个好的设计时?"


优点:

  • 减少代码重复:接口实现可重用
  • 在类的接口实现之间切换很容易
  • 仅查看基类就可以了解很多具体的实现

缺点:

  • 虚拟继承导致的调度性能命中
  • 不常见的模式,需要为外部/新人解释/记录

选择:

  • 如果需要接口层次结构,则没有好的替代方案

  • 否则,层次结构可能会分解为单独的接口

它可能看起来像这样:

struct IA
{
    virtual ~IA() = default;
    virtual void a() = 0;
};
struct A: public IA
{
    virtual ~A() = default;
    virtual void a() {}
};
struct IB
{
    virtual ~IB() = default;
    virtual void b() = 0;
};
struct B: public IB
{
    virtual ~B() = default;
    virtual void b() {}
};
struct C: public A, public B
{
};

有一个相对干净的解决方法。当您从 IB 继承 B 时,编译器要求您提供来自 IB 的所有抽象方法的实现,包括 IA。由于 a() 已经在 A 中实现,因此您可以在 B 中创建一个存根,该存根仅从 A 调用方法:

class IA
{
public:
    virtual void a() = 0;
};
class A: public IA
{
public:
    virtual void a()
    {
    }
};
class IB: public IA
{
public:
    virtual void b() = 0;
};
class B: public IB, public A
{
public:
    virtual void b()
    {
    }
    virtual void a()
    {
        A::a();
    }
};