Question

I have a quite special situation in my C++ program.

Look at the following class setup:

class Base1 {
  public: void baseMethod();
}

class Base2 : public Base1 {
  ...
}

class Common {
  public: void commonMethod();
}

class Derived1 : public Base1, public Common {
  ...
}

class Derived2 : public Base2, public Common {
  ...
}

Base1 and Base2 are unchangeable for me as they are part of a library.

What I want to achieve is that both Derived1 and Derived2 share the same method commonMethod(), so I use class Common with that method as a common base for Derived1 and Derived2.

The problem now is that commonMethod() shall contain a call to baseMethod() which is defined in Base1! In the context of a Derived1- or Derived2-object this is legal, but how to define that method in Common?

I know that if I would declare Base2 as virtual derived class from Base1 and the same for Common, it shouldn't be a problem (at least for Derived2, not sure about Derived1). But as I can't modify Base2 that's not possible anyway.

Also letting Common inherit from Base2 and then Derived1 and Derived2 solely from Common doesn't work because I don't want Derived1 to inherit from Base2!

What then came to my mind was to make a dynamic_cast within commonMethod():

void Common::commonMethod() {
  ...
  Base1* self = dynamic_cast<Base1*>(this);
  if(self) {
    self->baseMethod();
  }
  ...
}

This seems to work, but I'm not sure if this is a "nice" solution...

Do you have any ideas how to make it better? Or do you think this solution isn't bad at all? :)

Was it helpful?

Solution

If the only purpose of Common is to provide a common implementation of that one method, you can use the CRTP pattern and template it on the type of the base. At this point you could decide whether it makes sense to keep it as multiple bases of the DerivedX types or it could make sense to linearize the inheritance hierarchy:

// Option1
template <typename Derived>
struct Common {
   void commonFunction() { ... static_cast<Derived*>(this)->foo(); ... }
};
struct Derived1 : Base1, Common<Derived1>

// Option2 (not strictly CRTP, but close)
template <typename Base>
struct Common : Base {
   void commonFunction() { ... this->foo(); ... } // keep the this-> here
};
struct Derived1 : Common<Base1>

OTHER TIPS

If I were you, I'd choose composition over multiple inheritance, i.e. to define common as a member object of derived classes.

class Base1 {
  public: void baseMethod();
}

class Base2 : public Base1 {}

class Common {
  public: 
     Common(Base1 *base): m_base(base) {}
     void Common::commonMethod()
     {
        m_base->baseMethod();
     }
  private:
     Base1 *m_base;
}

class Derived1 : public Base1
{
  public:
     Derived2(): m_common(this) {}
  private:
     Common m_common;
}

class Derived2 : public Base2
{
  public:
     Derived2(): m_common(this) {}
  private:
     Common m_common;
}

There is a potential risk of going this way though. Since member object(Common) is constructed first before the outer object(Derived1 or Derived2), you want to make sure no methods from the Derivedx object is called in Common's constructor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top