1

I have an abstract class used by objects that want to use some fooization mechanism

#include <unordered_set>

class Fooable
{
public:
    Fooable() { registered.insert(this); }
    ~Fooable() { registered.erase(this); }
    virtual void fooify() = 0;

    static void fooify_all()
    {
        for(auto * f : registered)
            f->fooify();
    }

private:
    static std::unordered_set<Fooable*> registered;
};

std::unordered_set<Fooable*> Fooable::registered;

Then a base class (note the private inheritance):

class Fruit : private Fooable
{
    void fooify() override final { //Access class private members }
};

And a derived class

class Apple : public Fruit, private Fooable
{
    void fooify() override final { //Access class private members }
};

Both Apple and Fruit want to have their own private definition of fooify, which uses the class private variables and do stuff. And at the end fooify will be called for both class implementations, independently of each other.

The issue is, the compiler complains when Apple tries to override a virtual function marked with final. While those functions should be unrelated.

I could add levels of indirection, but this would make the code use lots of accessors or friend classes, as fooify does access a lot of private member variables.

Any idea to make this work or redesign it a nice way?

Example that fails to compile because of final: https://onlinegdb.com/CbcHXryX2

Example without final that compiles but shows Apple overrides indirectly inherited Fruit::fooify while I would like it to implement its directly inherited Fooable::fooify : https://onlinegdb.com/xH-MNxpVW

galinette
  • 8,896
  • 2
  • 36
  • 87
  • This is not a diamond problem. Your inheritance tree is a line, or rather it should be. `Fooable` looks more like a trait, and you would likely be better served using the CRTP to provide a mixin over standard inheritance. – sweenish Apr 24 '23 at 13:24
  • `private Fooable` This is an issue. What is purpose of the private inheritance? See https://stackoverflow.com/questions/656224/when-should-i-use-c-private-inheritance – 273K Apr 24 '23 at 13:25
  • @273K the purpose is that Fruit is not supposed to be castable to Fooable outside of the Fruit class (and not from derived classes) – galinette Apr 24 '23 at 13:28
  • If it is not castable, what is purpose of `virtual Fooable::fooify() = 0;`? – 273K Apr 24 '23 at 13:33
  • @sweenish `global_register_fooable` actually stores a vector of `Fooable`s, and this vector is used to call `fooify`, I could not do this using CRTP – galinette Apr 24 '23 at 13:35
  • @273K `global_register_fooable(this)` does append `this` to a `std::vector` vector, and this vector is used to call `fooify()` – galinette Apr 24 '23 at 13:37
  • Make the inheritance protected. Surprisely a user with such a high reputation have not give all required information as a [mcve] in the question. – 273K Apr 24 '23 at 13:39
  • Unfortunately for you, visibility is checked after name resolution... So `Apple` inherits twice from `Fooable` – Jarod42 Apr 24 '23 at 13:40
  • @273K you don't need to be that contemptuous. A MCVE is not always required to understand concepts, and if it is, you just could ask nicely. I'll edit the question and add one, no need to answer here if you have no goodwill. – galinette Apr 24 '23 at 13:47
  • Right now, nothing in the question indicates that CRTP isn't feasible. The global register could just have its type changed. Or are you saying that you also derive lots of other classes from Fooable, like Vegetables and Canned goods? Right now, everything you're saying about Fooable sounds like it should be a mixin, and you need a root class, like Product. – sweenish Apr 24 '23 at 13:47
  • @sweenish Wait a minute, I'll add more details and a verifiable example to the question. The issue I'm facing is we are trying to make a nice design out of an extremely Ill formed library we have no choice but to use and derive its classes from. So it's difficult to make the problem understandable without thousands of lines of junk, but I will try. – galinette Apr 24 '23 at 13:50
  • @sweenish If I understand right CRTP would consist in making `Fooable` a template class and derive `Fruit` from `Fooable` and Apple from `Fooable`. But then I can't keep a container of `Fooable*` pointers, which is the purpose of inheritance here. – galinette Apr 24 '23 at 13:57
  • That looks correct. Each type would then have its own exclusive `Fooable`. Your idea of container of `Fooable`s appears to be way off base. Again, everything you describe sounds like a trait. A container of traits makes little sense. Maybe you can just have a super class, like `Product`. Or you can just omit `final`. As it stands the error for trying to override a `final` method in a child class makes perfect sense. – sweenish Apr 24 '23 at 14:04
  • @sweenish but since I inherit Fooable twice, I am not expecting Apple::fooable() to override the Fruit::fooable(), and added the "final" to be sure it wasn't. Maybe this was a wrong idea. – galinette Apr 24 '23 at 14:10
  • @sweenish I added to online gdb examples that show the problem. – galinette Apr 24 '23 at 14:29
  • Perhaps that answer shows a way with two overriding base classes, but otherwise similar in intent: https://stackoverflow.com/questions/616380/multiple-inheritance-virtual-function-mess/616415#616415 also have a look at the comments – Sebastian Apr 24 '23 at 14:32

0 Answers0