解决涉及 C++ 中状态机的前向声明问题

发布于 2024-09-06 09:17:18 字数 2091 浏览 8 评论 0原文

我最近在中断一段时间后回到了 C++ 开发,并且有一个关于 状态设计模式的实现。我正在使用香草模式,完全一样 根据 GoF 的书。

我的问题是状态机本身是基于一些用作一部分的硬件 嵌入式系统 - 因此设计是固定的且无法更改。这导致 两个状态(特别是)之间的循环依赖,我正在尝试 解决这个问题。这是简化的代码(请注意,我尝试通过使用来解决此问题 标题像往常一样,但仍然有问题 - 我在这段代码片段中省略了它们):

#include <iostream>
#include <memory>

using namespace std;

class Context
{
public:
    friend class State;

    Context() { }

private:
    State* m_state;
};

class State
{
public:
    State() { }

    virtual void Trigger1() = 0;
    virtual void Trigger2() = 0;
};

class LLT : public State
{
public:
    LLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};


class ALL : public State
{       
public: 
    ALL() { }
    void Trigger1() { new LLT(); }
    void Trigger2() { new DH();  }
};  

// DL needs to 'know' about DH.
class DL  : public State
{           
public:
    DL() { }
    void Trigger1() { new ALL(); }
    void Trigger2() { new DH();  }
};      

class HLT :  public State
{
public:
    HLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};

class AHL : public State
{
public:
    AHL() { }
    void Trigger1() { new DH();  }
    void Trigger2() { new HLT(); }
};

// DH needs to 'know' about DL.
class DH  : public State
{
public:
    DH () { }
    void Trigger1() { new AHL(); }
    void Trigger2() { new DL();  }
};


int main()
{
    auto_ptr<LLT> llt (new LLT);
    auto_ptr<ALL> all (new ALL);
    auto_ptr<DL>  dl (new DL);
    auto_ptr<HLT> hlt (new HLT);
    auto_ptr<AHL> ahl (new AHL);
    auto_ptr<DH>  dh (new DH);  

    return 0;
}

问题基本上是在状态模式中,状态转换是由 调用 Context 类中的 ChangeState 方法,该方法调用 下一个状态的构造函数。

由于循环依赖,我无法调用构造函数,因为它是 不可能预先定义“问题”状态的两个构造函数。

我查看了 这篇文章,以及模板方法似乎是理想的解决方案 - 但它无法编译,而且我对模板的了解相当有限......

另一个想法我尝试向子类状态引入一个 Helper 类, 通过多重继承,看看是否可以指定基类的构造函数 并具有对状态子类的构造函数的引用。但我认为那是相当 雄心勃勃......

最后,直接实现工厂方法设计模式是否是最好的方法 解决整个问题?

I've recently returned to C++ development after a hiatus, and have a question regarding
implementation of the State Design Pattern. I'm using the vanilla pattern, exactly as
per the GoF book.

My problem is that the state machine itself is based on some hardware used as part of
an embedded system - so the design is fixed and can't be changed. This results in a
circular dependency between two of the states (in particular), and I'm trying to
resolve this. Here's the simplified code (note that I tried to resolve this by using
headers as usual but still had problems - I've omitted them in this code snippet):

#include <iostream>
#include <memory>

using namespace std;

class Context
{
public:
    friend class State;

    Context() { }

private:
    State* m_state;
};

class State
{
public:
    State() { }

    virtual void Trigger1() = 0;
    virtual void Trigger2() = 0;
};

class LLT : public State
{
public:
    LLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};


class ALL : public State
{       
public: 
    ALL() { }
    void Trigger1() { new LLT(); }
    void Trigger2() { new DH();  }
};  

// DL needs to 'know' about DH.
class DL  : public State
{           
public:
    DL() { }
    void Trigger1() { new ALL(); }
    void Trigger2() { new DH();  }
};      

class HLT :  public State
{
public:
    HLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};

class AHL : public State
{
public:
    AHL() { }
    void Trigger1() { new DH();  }
    void Trigger2() { new HLT(); }
};

// DH needs to 'know' about DL.
class DH  : public State
{
public:
    DH () { }
    void Trigger1() { new AHL(); }
    void Trigger2() { new DL();  }
};


int main()
{
    auto_ptr<LLT> llt (new LLT);
    auto_ptr<ALL> all (new ALL);
    auto_ptr<DL>  dl (new DL);
    auto_ptr<HLT> hlt (new HLT);
    auto_ptr<AHL> ahl (new AHL);
    auto_ptr<DH>  dh (new DH);  

    return 0;
}

The problem is basically that in the State Pattern, state transitions are made by
invoking the the ChangeState method in the Context class, which invokes the
constructor of the next state.

Because of the circular dependency, I can't invoke the constructor because it's
not possible to pre-define both of the constructors of the 'problem' states.

I had a look at this article, and the template method which seemed to be the ideal solution - but it doesn't compile and my knowledge of templates is a rather limited...

The other idea I had is to try and introduce a Helper class to the subclassed states,
via multiple inheritance, to see if it's possible to specify the base class's constructor
and have a reference to the state subclasse's constructor. But I think that was rather
ambitious...

Finally, would a direct implmentation of the Factory Method Design Pattern be the best way
to resolve the entire problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤檠 2024-09-13 09:17:18

您可以在类定义之外定义成员函数,例如,

class DL : public State
{
public:
    void Trigger2();
};

inline void DL::Trigger2() { new DH(); }

定义依赖于这些类定义之后的类定义的成员函数。仅当您在头文件中定义类的成员函数外部时,inline 关键字才是必需的。

顺便说一句,为什么你只在函数中使用 new DH() ?你到处都在泄漏内存!

You can define the member functions outside of the class definitions, e.g.,

class DL : public State
{
public:
    void Trigger2();
};

inline void DL::Trigger2() { new DH(); }

Define the member functions that rely on later class definitions after those classes are defined. The inline keyword is only necessary if you define the member function outside of the class in the header file.

As an aside, why are you just using new DH() in your functions; you're leaking memory everywhere!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文