We have a very common calculation Compute that can be done multiple ways. These inherit from some IFoo interface. We'll call them FooRed and FooBlue.
class FooRed : public IFoo
{
public:
FooRed() = default;
virtual double Compute() override final; //Inherited from IFoo.
}
A shared_ptr<IFoo> is distributed among many objects so that as they go about their business they can Compute in the same way. The original shared_ptr<IFoo> myFoo = make_shared<FooRed>() sits up above and gets handed out to objects as they get constructed: SubObject(myFoo).
Later in development, its decided that it may be useful for the calculation to change modes from FooRed to FooBlue during runtime. To this end, a template class is written
template<class T>
class Toggleable:
{
protected:
std::shared_ptr<T> _instance;
bool _state;
public:
Toggleable();
T* const Get() const {return _instance.get()};
const shared_ptr<T>& GetRef() const {return _instance};
virtual void Toggle(); //sets _instance to the correct type.
}
And the corresponding FooManager
class FooManager : public Toggleable<IFoo>
{
public:
virtual void Toggle() override; //Inherited from Toggleable
}
So now the UI or whatever has access to the original FooManager can Toggle it, and references to the internal state are handed out to the objects as needed: SubObject(myFoo->GetRef()). Everyone has the same reference so they all compute in the same way.
However, my first inclination was to make FooManager also implement IFoo itself, sort of like a Container pattern:
class FooManager : public Toggleable<IFoo>, public IFoo
{
public:
virtual void Toggle() override; //Inherited from Toggleable
virtual double Compute() override {return Get()->Compute();} //Inherited from IFoo
}
This way, you don't have to change the constructor calls and the implementation of the toggle changes as little of the underlying code as possible. Everyone who already had or was passed an IFoo still sees it as one, and only the parts that now handle the toggling need to see that object as a FooManager or Toggleable.
I also think its more consistent for constructors, since if Foo is Toggleable but Bar isn't, a subobject that needs to do both is constructed with SubObject(myFoo->GetRef(), myBar) in an awkward mix of references to shared pointers and shared pointers. But my coworker said that this sort of multiple inheritance is bad practice, and that this structure muddies the behavior of a manager and the actual Foo.
Is this good practice? How should one properly implement a run-time toggle like this that needs to switch between multiple sub-elements?
toggleableas it's not thread safe. It would suck if one thread toggled while anther thread had a reference checked out fromGetRef.