will
will

Reputation: 151

C++ interfaces and inheritance

I want to have an interface IA and another that extends it IB.

A then implements IA, and B inherits A and also implements IB.

However when compiling B gets errors saying the IA stuff is undefined, even though A defined it all :(

class IA
{
public:
    virtual ~IA(){}
    virtual void foo()=0;
};
class IB : public IA
{
public:
    virtual void bar()=0;
};


class A : public IA
{
public:
    A();
    void foo();
};
class B : public A, public IB
{
public:
    B();
    void bar();
};

error C2259: 'B' : cannot instantiate abstract class
due to following members:
'void IA::foo(void)' : is abstract

Upvotes: 14

Views: 1611

Answers (4)

NPE
NPE

Reputation: 500933

Take a look at the C++ FAQ, from the following point onwards: https://isocpp.org/wiki/faq/multiple-inheritance#mi-diamond

It explains the "dreaded diamond" and virtual inheritance in some detail.

Upvotes: 17

Alexandre C.
Alexandre C.

Reputation: 57006

This is the real fully justified case for virtual inheritance which is not always a design smell.

In the case of parallel hierarchies interface / implementation, every inheritance relation of the form "any class -> interface" should be marked virtual: class A : public virtual IA; class B : public virtual IB, public A and class IB : public virtual IA.

This way, likely (implementation dependant but at least conceptually), an extra pointer is stored in each virtually derived class to know where it should find its virtual base. Class A, B and IB will have a pointer to IA, and class B will have a pointer to IB. Each virtual base will also have its own vtable.

The "dreaded diamond" point of view is graphically nice, but the point is that derived classes should know where the base class they will use reside, and that is where virtual inheritance kicks in. You clearly need a vtable per interface here, and virtual inheritance allows you to do just that.

Then you can continue paralleling, and add extra classes C, IC, and so on, just remember:

Whenever you inherit an interface, inherit virtually.

By the way, COM classes have similar design.

Upvotes: 5

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385405

(No, A does not define anything. You declared A() and void foo(), but you did not define them.)

The real problem is your multiple inheritance.

       B
     /   \
   A      IB
  /         \
IA          IA

As you can see, you have two "versions" of IA in your inheritance tree, and only A implements void IA::foo (though, as I noted above, this will give you a linker error as you didn't define the implementation).

void IB::IA::foo() remains unimplemented; thus, B itself "inherits the abstractness" and you can't instantiate it.

B will have to implement void foo() as well, or you might be able to use virtual inheritance to hack around it.

Upvotes: 6

Bo Persson
Bo Persson

Reputation: 92391

You have two copies of foo(), one inherited from IB::IA and one from A::IA. Only one of those have a non-abstract version in A.

Upvotes: 1

Related Questions