0

I'm trying to rewrite a piece of code in c++ to isolate a piece of code that I would like to use only in some of the children of a particular object.

I've created a very simplified version of the code just to analyze the problem:


class SaverInterface {
protected:
    virtual void saveData(int data) = 0;
};

class SaverImpl : public SaverInterface {
protected:
    void saveData(int data) override {
        std::cout << "data to save: " << data << std::endl;
    }
};

class ObjectA : public SaverInterface {
public:
    void save(int data) {
        saveData(data);
    }
};

class ComposedObjectA : public ObjectA, public SaverImpl {
public:
    void publicSave() {
        save(1);
    }
};

int main() {
    auto* objectA = new ComposedObjectA();
    objectA->publicSave();

    delete objectA;
    return 0;
}

The idea is that I have different ways of saving some data and I would like to abstract that operation in the intermediate object (ObjectA), calling the pure virtual function of the interface (SaverInterface), that is implemented in an other object (SaverImpl).

In my "final" composed object (ComposedObjectA) I've tried to derive from both the ObjectA and SaverImpl, thinking that the compiler would take the saveData function implementation from the SaverImpl, but it's not working, and the compiler gave me back the error "unimplemented pure virtual method 'publicSave' in 'ComposedObjectA'".

I'm relatively new to the polymorphism (I've written code for years in language that haven't that option) so I'm probably assuming something that the compiler cannot do... Someone could explain me why that code couldn't work?

Any suggestion on different approach to solve the situation?

Thanks to all Cheers Mix

Mix Kira
  • 107
  • 1
  • 8
  • 2
    You should use `virtual public` inheritance. Otherwise, the base interfaces are independent in the composed object class. – Eljay May 28 '23 at 12:49
  • 1
    Alternatively, ComposedObjectA needs a thunk method `void saveData(int data) override { SaverImpl::saveData(data); }` to forward to the SaverImpl's method. – Eljay May 28 '23 at 13:17
  • One trick; make `SaverImpl` a template, as in `template class SaverImpl : public T {...};` Now you can write `class ComposedObjectA : public SaverImpl {...};` The idea is to be able to inject SaverImpl into a linear inheritance hierarchy, rather than bolting it on to the side. – Igor Tandetnik May 28 '23 at 13:30

1 Answers1

1

You have a diamond inheritance problem. If you really want to continue down this path, you will need to use virtual inheritance (so : public SaverInterface becomes : virtual public SaverInterface in both places).
Demo

However, do you really want inheritance in this case? What does it mean for ObjectA to be a Saver? Does it just mean that is has a saveData member function? In this case, why not use a function pointer instead?

Example:

class SaverInterface {
protected:
    using SaveDataFunction = void (*)(int);

    SaverInterface(SaveDataFunction saveData) : saveData(saveData) {}

    SaveDataFunction saveData;
};

class ObjectA : public SaverInterface {
public:
    ObjectA(SaveDataFunction saveDataFunction) : SaverInterface(saveDataFunction) {}

    void save(int data) {
        saveData(data);
    }
};

Demo

You can either keep the SaverInterface class or just implement the function pointer directly in ObjectA.

Nelfeal
  • 12,593
  • 1
  • 20
  • 39
  • Thanks for the answer and for pointing me to the diamond inheritance problem :) About your solution, I have simplified the problem with only one function, but I will probably need some other functions and parameter, and with your approach I need a pointer for all of them, and I would prefer to group them in a class. Does your approach have performance benefit on a solution with virtual inheritance? – Mix Kira May 28 '23 at 13:42
  • @MixKira Virtual inheritance requires a virtual table, which is a table of function pointers. So the performance should be about the same as having a group of function pointers in `SaverInterface`. I just find inheritance in general to be detrimental, especially [implementation inheritance](https://stackoverflow.com/questions/3774204/difference-between-interface-inheritance-and-implementation-inheritance) (basically what `SaverImpl` produces). Without the whole code, I can only speculate. – Nelfeal May 28 '23 at 13:50