Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual inheritance and interfaces

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()
    {
    }
};

Do you always inherit your interfaces as virtual as I do above? If not, how would you impement the above code?

like image 750
Baz Avatar asked Jun 26 '12 10:06

Baz


2 Answers

Using multiple inheritance coupled with virtual inheritance is an appropriate design choice when it comes to separating interface and implementation hierarchies. E.g., see: "When virtual inheritance IS a good design?"


Pros:

  • less code duplication: interface implementations made re-usable
  • switching between the interface implementations for a class is easy
  • just looking at base classes tells a lot about concrete implementations

Cons:

  • dispatching performance hit cased by virtual inheritance
  • uncommon pattern, needs to be explained/documented for external/new people

Alternatives:

  • no good alternatives if interface hierarchy is needed

  • otherwise, the hierarchy could be broken into individual interfaces

It could look something like:

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
{
};
like image 102
AMA Avatar answered Oct 22 '22 12:10

AMA


There is one relatively clean workaround. When you inherit B from IB, the compiler requires your provide an implementation of all abstract methods from IB including IA. As a() is already implemented in A, you can create a stub in B that simply invokes a method from 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();
    }
};
like image 32
Ivan Shcherbakov Avatar answered Oct 22 '22 12:10

Ivan Shcherbakov