Scott Tiger
Scott Tiger

Reputation: 488

Call a common named method of all base classes from a derived class with multiple inheritance

I realize that what I am trying to do is possibly wrong, so I would gladly accept and alternative approach. All code below is just an illustration.

Suppose I have a derived class, with multiple base classes:

template<typename... Bases> class Derived : public Bases...{
public:
    VariadicTemplate(BaseClasses&&... base_classes) : BaseClasses(base_classes)... {}

    void DoAllFoo();
};

And all the base classes have a method, named DoFoo(). I was going to derive them from a common base with a public method Foo():

class CommonBase {
public:
    virtual Foo() { DoFoo() };
protected:
    virtual void DoFoo() = 0;
};

class Base1 : public CommonBase {
    DoFoo() { /* displays something */ };
};

class Base2 : public CommonBase {
    DoFoo() { /* displays something else */ };
};

....

Now this is how I was going to use it. I want to instantiate some amount the Derived class objects, specified with different Base classes:

Devired<Base1, Base2> x;
Devired<Base5, Base7, Base21> y;
...
x.DoAllFoo();
y.DoAllFoo();

I want (somehow) the Derived's DoAllFoo() to "iterate" over it's Base classes and call each classes Foo() method.

The only solution I can imagine is to have some set of function pointers/functors/whatever in Derived and make all Bases register their Foo() method in this set when constructing. This will probably work, but look like it could be done better.

I hope, that I am not familiar with some common pattern to solve this problem (or I am just pure wrong), so please advise. Thank you.

Upvotes: 2

Views: 249

Answers (2)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48447

You want either:

void DoAllFoo()
{
    using expand = int[];
    static_cast<void>(expand{ 0, (static_cast<Bases*>(this)->Foo(), void(), 0)... });
}

or:

void DoAllFoo()
{
    using expand = int[];
    static_cast<void>(expand{ 0, (Bases::Foo(), void(), 0)... });
}

depending on whether the call to Foo itself should be virtual or not.

Upvotes: 3

Emerald Weapon
Emerald Weapon

Reputation: 2540

The pattern I would use is simply composition as opposed to inheritance. Why don't you just make objects of base classes as members of what you now call Derived? You can simply store them into a std::vector and then iterate over it inside DoAllFoo.

For example:

class FooWrapper {

// ...

public:
  void DoAllFoos();

private:
  std::vector<std::unique_ptr<CommonBase> > bases_;   


} 

void FooWrapper::DoAllFoos() 
{
   for(auto& base: bases)
     base->DoFoo();
}

Upvotes: 1

Related Questions