14

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

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
will
  • 151
  • 1
  • 4

4 Answers4

17

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.

Atul Kumar
  • 366
  • 4
  • 15
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • +1 damn I'm too slow. Stupid portal proxy server and content checking software at my company... – wheaties Apr 07 '11 at 13:33
  • 2
    @wheaties: It's not a race. :) – Lightness Races in Orbit Apr 07 '11 at 13:34
  • @Tomalak: What do you mean? Only the first mouse to answer the question (even half-way) gets the cheese! – FreeAsInBeer Apr 07 '11 at 13:41
  • ok, so I virtuall inherit the interfaces, and it seems to work. But now I get a "warning C4250: 'B' : inherits 'A::A::foo' via dominance". The msdn page just seems to say what it is, not how to get rid of it short of a #pragma warning to kill that warning... I assume there is aparticular way to do things that doesnt generate compile warnings? – will Apr 07 '11 at 13:44
  • @will: Use a less strange inheritance tree. :) (*ducks*) – Lightness Races in Orbit Apr 07 '11 at 13:51
  • It seems to me to be perfectly valid to have one interface extend another, and it also seems perfectly valid that when implementing that interface, I might as well use the implementation of the other as a base... – will Apr 07 '11 at 13:54
  • @will Take a look at http://stackoverflow.com/questions/469508/visual-studio-compiler-warning-c4250-class1-inherits-class2member-via-do – NPE Apr 07 '11 at 14:18
  • @will: C4250 is a well-known Microsoft "silly warning" -- it's perfectly safe to disable it using a #pragma. – Stuart Golodetz Apr 07 '11 at 15:22
6

(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.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
5

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.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
1

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.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203