在没有指针的情况下以C 实施策略模式

Implement Strategy Pattern in C++ without Pointers

本文关键字:施策略 策略 模式 指针 情况下      更新时间:2023-10-16

我的目标是在没有手动内存分配的情况下对策略模式进行C 实现。从概念上讲,我给出的示例中,我不认为这是必要的。此外,手动内存管理容易出错。请记住,我的示例只是MWE,实际上所有对象都更复杂,并且手动内存管理通常会引入错误。


在下面的示例中,需要给出 Base类要构造的Strategy,将其用于在其方法getStrategyDecision()中产生输出。当然,它可以不是一个Strategy,因为该类是抽象的,因此该参数必须是参考。由于我上述原因,它不是指针。

以下代码 dis 编译,但是,因为在多个地方添加了 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构造函数的参考参数是非法的。

我可以理解这个错误,但是

  1. 当一切都是const时,为什么它可以工作?这似乎表明它应该在没有const的情况下工作,而我只是缺少一些东西。
  2. 我什至不想要" 临时"对象,我必须这样做的唯一原因是因为我无法通过Strategy本身,因为该类是抽象的。

再次,我知道我可以通过将变量strategy作为Strategy的指针并将new AlwaysZero()传递给Base构造函数来解决此问题。如上所述,这就是我不想要的。


我的问题是双重的。首先,我想知道为什么如果没有const,我的示例为什么会编译。我想了解这里发生了什么。

其次,我想知道是否可以修改此示例,以便strategy不再是const(并且它有效(,而是不使用任何类型的指针。仅当第二个问题的答案是"否" ,我才会开始寻找避免问题的巧妙方法(如评论中建议的智能指针(。

ps:我将G 用作编译器。它可能无关紧要。

您的代码编译的原因是const引用延长了临时的寿命,但非const reference却没有。有关详细说明

至于为什么 C 标准表示非const参考不会延长暂时的寿命。如下所述,非const reforences首先不能绑定到临时性。有关原因。

的简单示例,请参见此处。

因此,您的技术应该很好。但是,如果您想要其他选项...

策略模板

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); }
};