我的目标是在没有手动内存分配的情况下进行Strategy Pattern的C ++实现。从概念上讲,我不觉得在我给出的例子中它应该是必要的。此外,手动内存管理容易出错。请记住,我的示例只是一个MWE,实际上所有对象都更复杂,手动内存管理经常会引入错误。
在下面的示例中,需要为类Base
提供要构造的Strategy
,它将用于在其方法getStrategyDecision()
中生成输出。当然,它可以不给予Strategy
因为该类是抽象的,所以这个参数必须是一个引用。由于上述原因,不是指针。
以下代码执行编译,但仅,因为const
已添加到多个位置。
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();
}
如果删除const
限定符,则会失败,因为在Main
的构造函数中,将临时对象AlwaysZero()
传递给Base
的构造函数的引用参数是非法。
我能理解这个错误,但是
const
时才有效?这似乎表明它应该在没有const
的情况下同样有效,我只是遗漏了一些东西。Strategy
本身,因为该类是抽象的。同样,我知道我可以通过将变量strategy
指向Strategy
并将new AlwaysZero()
传递给Base
构造函数来解决此问题。这就是我不想要的,如上所述。
我的问题是双重的。首先,我想知道为什么我的例子编译,当它没有const
时。我想了解这里发生了什么。
其次,我想知道是否可以修改此示例,以便strategy
不再是const
(并且它可以工作),但不使用任何类型的指针。只有当第二个问题的答案是“no”时,我才会开始寻找避免问题的聪明方法(例如智能指针,如评论中所建议的那样)。
PS:我使用g ++作为编译器。它可能会或可能不重要。
答案 0 :(得分:3)
您的代码编译的原因是const引用延长了临时的生命,但非const引用却没有。有关详细说明,请参阅https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/。
至于为什么 C ++标准说非const引用并没有延长临时的寿命。正如here所解释的那样,非const引用不能首先绑定到临时值。有关原因的简单示例,请参阅here。
所以,你的技术应该可以正常工作。但如果你想要其他一些选择......
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()) {}
};
您可以使用指针而无需手动内存管理。只要它们是非拥有指针。
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); }
};