c++strategy-patterncovariant-return-types

Strategy Pattern and Covariant Return Type in C++


class Context{
public:
    Strategy* strategy;
    void PickStrategy(Strategy *strategy){
        delete this->strategy;
        this->strategy = strategy;
    }

    C* execute(string some_text) const{
        return this->strategy->execute(std::move(some_text));
    }
};
class C{

};

class D: public C{

}
class MyStrategy: public Strategy{
    D* execute(string some_text){
        // business logic
        return pointer_to_D;
    }
}

Client-side:

auto context = Context();
context.PickStrategy(new MyStrategy());
auto output1 = context.execute("some_text");
auto output2 = context.execute("some_text2");
if (output1 == output2){
    // business logic
}
bool operator==(const D& d1, const D& d2){
    // business logic
}

I have an application I thought employing the strategy pattern would make huge sense. So I resolved at employing it. But my question is that without touching the client-side at all, can I use my overloaded operator determined specifically to a particular product that is supposed to be returned by a picked strategy by the context. As you know, we're allowed to return the derived class objects in our virtual overridden function implementations in C++, which is called covariant return type, but auto reference assumes the most generic type in the hierarchy in this case which leads to being unable to use overloaded operators as intended, though I want it to change in runtime depending on the chosen strategy within the context without bothering doing any extra nasty monolithic dynamic_cast checks since if I do that, it turns out that there would be no sense to use strategy pattern. So, how can I use covariant return type through the context object in my case?


Solution

  • This is a perennial problem. The core issue is, Context wants to have dynamic control of its strategy (including the dynamic type of its return value) but its users want static assurances on that return value. You can template Context on the strategy and/or on the return type, and potentially template Strategy on the return type, but fundamentally you’ll need to introduce the limits on the return type at compile time or you’ll need unsafe casting at runtime.