Implement a C ++ strategy pattern without pointers
My goal is to implement a C ++ implementation of the Strategy Pattern without manual memory allocation. I don't feel like this should be necessary in the example I am giving, conceptually speaking. Also, manual memory management is error prone. Keep in mind that my example is just an MWE, in fact all objects are more complex and manual memory management often introduces errors.
In the example below, the class Base
must be given a constructed Strategy
one that it will use to output the output in its method getStrategyDecision()
. Of course, it may not be assigned Strategy
because this class is abstract, so this argument must be a reference. For my reasons, this is not a pointer.
The following code compiles, but only because it const
was added in multiple places.
class Strategy {
public:
virtual int decision() const = 0;
};
class AlwaysZero : public Strategy {
public:
int decision() const { return 0; }
};
class Base {
private:
Strategy const &strategy;
public:
Base(Strategy const &s) : strategy(s) {}
int getStrategyDecision() {
return strategy.decision();
}
};
class Main : public Base {
public:
Main() : Base(AlwaysZero()) {}
};
int main ()
{
Main invoker;
return invoker.getStrategyDecision();
}
If you remove qualifiers const
it fails because, in the constructor, Main
passing a temporary object AlwaysZero()
into a constructor reference argument Base
is illegal.
I could understand this error, but
- Why does it work when everything is
const
? This seems to suggest it should work withoutconst
equally well, and I was just missing something. - I don't even need a "temporary" object, the only reason I have to do this is because I cannot pass it myself
Strategy
, because the class is abstract.
Again, I know I can solve this problem by specifying a Strategy
pointer to the variable Strategy
and passing it new AlwaysZero()
to the constructor Base
. This is what I don't want, as explained above.
My question is twofold. First, I want to know why my example compiles when not without const
. I want to understand what's going on here.
Second, I would like to know if this example can be modified so that it Strategy
no longer const
(and it works), but without using any pointer. Only if the answer to this second question is “no,” will I start looking for clever ways to avoid the problem (eg smart pointers, as suggested in the comments).
PS: I am using g ++ as my compiler. It may not matter.
source to share
The reason your code compiles is because a constant reference extends the lifetime of the temporary, but a non-constant reference does not. See https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ for details .
As for why the C ++ standard says that a non-const reference does not extend the lifespan. As explained here , non-const references cannot be bound to temporal parameters in the first place. See here for a simple example of why.
So your technique should work fine. But if you want other options ...
Strategy pattern
template<typename T>
class Base {
private:
T strategy;
public:
Base(const T& s) : strategy(s) {}
int getStrategyDecision() {
return strategy.decision();
}
};
class Main : public Base<AlwaysZero> {
public:
Main() : Base(AlwaysZero()) {}
};
Not owning pointer
You can use pointers without manual memory management. They don't own pointers yet.
class Base {
private:
Strategy *strategy;
protected:
void setStrategy(Strategy& s) { strategy = &s; }
public:
int getStrategyDecision() {
return strategy->decision();
}
};
class Main : public Base {
AlwaysZero my_strategy;
public:
Main() { setStrategy(my_strategy); }
};
source to share