6
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?

Mesop
  • 5,187
  • 4
  • 25
  • 42
Baz
  • 12,713
  • 38
  • 145
  • 268
  • 1
    Take a look at [this](http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9) – Mohammad Jun 26 '12 at 10:22
  • possible duplicate of [In C++, what is a virtual base class?](http://stackoverflow.com/questions/21558/in-c-what-is-a-virtual-base-class) – badgerr Jun 26 '12 at 10:25
  • If the hierarchy has to be like that, then virtual inheritance is the only choice, but in most cases in C++ you don't end up with that type of design. There are few cases where I have used virtual inheritance in my professional life... – David Rodríguez - dribeas Jun 26 '12 at 12:39
  • This kind of design happens, but hopefully very rarely. In any case, it has to be thought beforehand, and weighed against other possibilities, since sometimes you can't just add `virtual` to third party code. – Alexandre C. Jun 26 '12 at 14:33
  • 1
    @David Rodríguez But if I'm using inheritance between interfaces then I will have to use virtual inheritence, as in the example above, right? What design alternatives do I have? – Baz Jun 28 '12 at 11:28
  • @Baz: I am not saying this is not the solution for your particular problem, but inheritance among *interfaces* is not common in C++ (it is in the COM subdomain but I have not seen it in a real application outside of COM interfaces) – David Rodríguez - dribeas Jun 28 '12 at 13:27
  • @AlexandreC. "_This kind of design happens, but hopefully very rarely._" why do you write "hopefully"? What is the issue with this design? – curiousguy Aug 04 '12 at 22:36
  • @curiousguy: it's quite heavy to write. You have to maintain two parallel hierarchies (and forward some methods by hand), not forget the virtual keywords (rule of thumb: whenever you inherit an interface, inherit virtually), it adds one extra pointer in each class for each interface (performance hit), and dispatching is usually slower with virtual inheritance. This is something you ought to make sure you want, because it's not the simplest thing to do. – Alexandre C. Aug 05 '12 at 06:05
  • @AlexandreC. I have never seen a case where a forwarding was necessary. – curiousguy Jan 08 '17 at 07:04

2 Answers2

3

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
{
};
Community
  • 1
  • 1
AMA
  • 4,114
  • 18
  • 32
2

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();
    }
};
Ivan Shcherbakov
  • 2,063
  • 14
  • 23