本书Strategy Pattern中的Head First Design Patterns示例是用C++在[here]编写的。我正在尝试根据Effective GoF Patterns with C++11 and Boost将其转换为C++ 11样式,如下所示。

Quack 行为:

struct Quack {
    static void quack()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct MuteQuack {
    static void quack()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

Fly 行为:
struct FlyWithWings {
public:
    static void fly()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct FlyNoWay {
public:
    static void fly()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

Duck 层次结构:
class Duck
{
public:
    typedef std::function<void(void)> QUACK;
    typedef std::function<void(void)> FLY;

public:
    Duck(const QUACK &q, const FLY &f)
        : m_Quack(q), m_Fly(f) {}

    virtual ~Duck()
    {
    }

    void perform_quack()
    {
        m_Quack();
    }
    void perform_fly()
    {
        m_Fly();
    }

protected:
    QUACK   m_Quack;
    FLY     m_Fly;

private:
    Duck(const Duck&) = delete;
    Duck& operator=(const Duck&) = delete;
};

class MallardDuck
    : public Duck
{
public:
    MallardDuck()
        : Duck(&Quack::quack, &FlyWithWings::fly)
    {
    }
};

class PaintedDuck
    : public Duck
{
public:
    PaintedDuck()
        : Duck(&MuteQuack::quack, &FlyNoWay::fly)
    {
    }
};

到目前为止,客户工作良好。
int main()
{
    MallardDuck x1;
    x1.perform_quack();
    x1.perform_fly();

    PaintedDuck x2;
    x2.perform_quack();
    x2.perform_fly();

    return 0;
}

现在,我想将一个新的类RubberDuck扩展到层次结构,并且RubberDuck使用具有对象状态的新的飞行行为FlyWithRocket。如下:

一种新的 Fly 行为:
class FlyWithRocket {
public:
    FlyWithRocket() : m_Energy(3) {}
    void fly()
    {
        if(m_Energy > 0)
        {
            fly_with_rocket();
            --m_Energy;
        }
        else
        {
            fly_out_of_energy();
        }
    }

private:
    void fly_with_rocket()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
    void fly_out_of_energy()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    unsigned int m_Energy;
};

新的类型:
class RubberDuck
    : public Duck
{
public:
    RubberDuck()
        : Duck(&MuteQuack::quack, std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket)))
        , m_flyrocket()
    {
    }
private:
    FlyWithRocket m_flyrocket;
};

从现在开始,我想知道成员初始化顺序的规则。基本Duck在成员m_flyrocket之前初始化,但是请注意,基本Duck是使用尚未初始化的绑定(bind)m_flyrocket初始化的。
结果是,当我在VS2013中运行该程序时,该程序在运行时不会出现任何问题。

但是代码实际上不安全吗?如果没有,如何修改为更好的设计?

最佳答案

这是不安全的,但是除非您从基类构造函数中调用m_Fly(),否则不太可能破坏它。

不过,您可以通过以下两种方法轻松避免这种情况:

  • 为基类构造函数提供一个虚拟或默认构造的std::function,然后将m_Fly重新分配给派生类构造函数中的绑定(bind)仿函数
    RubberDuck()
        : Duck(&MuteQuack::quack, std::function<void()>())
    {
        m_Fly = std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket));
    }
    
  • FlyWithRocket本身用作仿函数(只需将void fly重命名为void operator()),然后按值传递它而不是保留私有(private)成员(它将由m_Fly函数对象拥有,并且您可以根据需要通过std::function::target<FlyWithRocket>()访问它)
    class FlyWithRocket {
    public:
        FlyWithRocket() : m_Energy(3) {}
        void operator() () {
    // ...
    
    RubberDuck()
        : Duck(&MuteQuack::quack, FlyWithRocket()) {}
    
  • 关于c++ - 具有状态的C + 11战略模式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23360892/

    10-10 02:38