views:

97

answers:

2

The scenario generating this is quite complex so I'll strip out a few pieces and give an accurate representation of the classes involved.

/* This is inherited using SI by many classes, as normal */
class IBase
{
 virtual string toString()=0;
};

/* Base2 can't inherit IBase due to other methods on IBase which aren't appropriate */
class Base2
{
 string toString()
 {
  ...
 }
};

/* a special class, is this valid? */
class Class1 : public IBase, public Base2
{
};

So, is this valid? Will there be conflicts on the toString? Or can Class1 use Base2::toString to satisfy IBase? Like I say there are lots of other things not shown, so suggestions for major design changes on this example are probably not that helpful... though any general suggestions/advice are welcome.

My other thought was something like this:

class Class1 : public IBase, public Base2
{
 virtual string toString()
 {
   return Base2::toString();
 }
};

This builds and links, but I've no idea if it has hidden bugs.

+1  A: 

You can fix this using "virtual inheritance".

Consider creating a common base class that only defines a pure virtual toString method (or, in reality, pure virtual version of whatever methods it makes sense for both IBase and Base2 to have), e.g.

class Stringable {
  public:
    virtual string toString() = 0;
};

Then, have both IBase and Base2 inherit from this Stringable class:

class IBase : public Stringable
{
};

class Base2 : public Stringable
{
public:
   virtual string toString()
   { ... }
};

Now this as it is still won't work because Class1 will have inherited two copies of the Stringable base class, only one of which has an implementation for toString in its inheritance hierarchy. This is known as the "dreaded diamond". However, if IBase and Base2 were to inherit virtually from Stringable, like this:

class IBase : virtual public Stringable
{
};

class Base2 : virtual public Stringable
{
public:
   virtual string toString()
   { ... }
};

Then this tells the compiler that there should only be one common Stringable base class even if IBase and Base2 are both inherited by one class, which is exactly what you want, because then the Base2::toString is used for Class1.

Your second idea has no "hidden bugs", but is somewhat of a pain in the butt to implement repeatedly, as you probably realize.

Tyler McHenry
+1  A: 

This should work just fine.

You're properly overriding the IBase interface to provide a definition of ToString() that will be forwared up to Base2::ToString().

Note that Base2 doesn't declare toString() as virtual, so Class1 can't override the behavior of Base2::ToString. No ambiguity there.

And, in addition, this is not the classic diamond problem in multiple inheritance solved by virtual inheritance because they don't share a base class.

Stephen