gpt4 book ai didi

c++ - 带状态的 C+11 策略模式

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:27:27 25 4
gpt4 key购买 nike

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

嘎嘎行为:

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

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

飞行行为:

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

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

新的飞行行为:

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

一个新的 Duck 类型:

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(),否则不太可能损坏来自基类构造函数。

不过,您可以通过以下任一方式轻松避免这种情况:

  1. 为基类构造函数提供一个虚拟的或默认构造的 std::function ,并重新分配 m_Fly到派生类构造函数中的绑定(bind)仿函数

    RubberDuck()
    : Duck(&MuteQuack::quack, std::function<void()>())
    {
    m_Fly = std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket));
    }
  2. 制作 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com