Virtual function in member initializer list, inheritance of nested class and virtual inheritance

I made a quite complex class design with multiple inheritance and inheritance of nested classes.

Here is what I am trying to achieve:

class ContainerBase
{
... // Pure virtual functions eg. list(), update()
protected:
    class ItemBase { ...  // Pure virtual functions eg. getName(), update()}
    virtual ItemBase* getItem() = 0
}

class ItemAContainer: public virtual ContainerBase
{
...// Overriding ContainerBase functions
protected:
    class ItemA: public ContainerBase::ItemA { ... // Overriding ItemBase functions }
    virtual ItemBase* getItem() override
    {
        return new ItemA()
    }
}

class ItemBContainer: public virtual ContainerBase
{
protected:
    class ItemB: public ContainerBase::ItemB { ... // Overriding ItemBase functions}
    virtual ItemBase* getItem() override
    {
        return new ItemA()
    }
}

class SingleItemContainer: public virtual ContainerBase
{
public:
    SingleItemContainer(): item(getItem())
    ...
    getName() {item->getName()}
    list() { item->list()}
protected:
    ItemBase *item;
private:
}

class MultipleItemContainer: public virtual ContainerBase
{
public:
    addItem() { items.emplace_back(getItem()); }
    BaseItem *operator[](size_t pos) { return items[pos]}
    ...
protected:
    vector<ItemBase*> items;
private:
}

The design works for me because first it allows me to customize my container.

class MyContainer: public virtual ContainerBase, public ItemAContainer, public SingleItemContainer
{ MyContainer():ContainerBase(), ItemAContainer(), SingleItemContainer()}

And second it enables a very flexible polymorphism.

MultipleItemContainer *a = new MyContainer() // ok
ItemAContainer *b = new MyContainer() // ok

However, the problem I have is with this line of code.

...
    class SingleItemContainer: public virtual ContainerBase
    {
    public:
        SingleItemContainer(): item(getItem()) // not working
        ...

getItem() is supposed to give the right type of item based on the class I have inherited (ItemAContainer or ItemBContainer). It works fine with MultipleItemContainer which calls addItem(). But because in SingleItemContainer, getItem() is called in a constructor, it is not dynamically bounded to ItemAContainer::getItem() or ItemBContainer::getItem()

What is the solution or workaround to this problem? Or is my class design a bad design?

1 answer

  • answered 2020-06-27 05:28 charliepu123

    Here are two solutions I can think of.

    1. Use class templates, like SingleItemContainer<ItemB>. The problem is that information about the object it contains will be lost when you want to take advantages of polymorphism.
    2. Avoid virtual functions in the constructor. That means to do something like container.init(). This is the easiest way but it also makes the entire class not so intuitive to use.