将"this"从父类方法转换为子类方法是一种好的做法吗?

Is casting "this" from a parent class method to a child a good practice?

本文关键字:类方法 一种 父类 this 转换      更新时间:2023-10-16

我正在实现一个非常基本的基类来运行有限状态机。这是我所做的...

/**
 * @class FSM
 * @brief This class is a base class for an object that wants to run a Finite State Machine.
 * That object, let's say States, would need to inherit from FSM<States>,
 * and its methods would then be available as state actions of the state machine.
 */
template<typename States>
class FSM
{
    public :
        /**
         * @typedef StateAction is an alias for a pointer to a method of States, only callable that can be a state of the FSM
         */
        typedef void(States::*StateAction)(void);
        /**
         * @fn FSM(States* states, StateAction initial_state_action = nullptr)
         * @brief Constructs a FSM object whose actions are of type StateAction
         */
        FSM(States* states, StateAction initial_state_action = nullptr)
        :
            m_states(states),
            m_state_action(initial_state_action),
            m_is_entering_state(true)
        {}
        /**
         * @fn bool update()
         * @brief Performs an iteration of the FSM
         * @returns true if and only if the FSM has a state to run
         */
        bool update()
        {
            if(m_states && m_state_action)
            {
                auto previous_action = m_state_action;
                (m_states->*m_state_action)();
                m_is_entering_state = (m_state_action != previous_action);
            }
            return m_state_action != nullptr;
        }
    protected :
        /**
         * @fn void setState(StateAction state_action)
         * @brief Change the state of the FSM
         * @param[in] state_action Method of States that implements the new state behavior (nullptr stops the FSM)
         */
        void setState(StateAction state_action)
        {
            m_state_action = state_action;
        }
        /**
         * @fn bool isEnteringState() const
         * @brief Tells whether the current state has just be entered or is looping, waiting for a transition
         * @returns] true if and only if the current state hasn't yet been executed since it has been changed
         */
        bool isEnteringState() const
        {
            return m_is_entering_state;
        }
    private :
        States*     m_states;            //!< Pointer to the child class that implements the States of the FSM
        StateAction m_state_action;      //!< Pointer to the method of States that implements the current state behavior
        bool        m_is_entering_state; //!< Tells whether the current state has just be entered or is looping, waiting for a transition
};

。以及它的使用方式:

class States : public FSM<States>
{
    public :
        States()
        :
            FSM<States>(this, &States::state1)
        {}
        void state1()
        {
            // Actions to perform when entering the state
            if(isEnteringState())    cout << "Entering ";
            // Actions to perform constantly (regulate a system, detect events, etc...)
            cout << __func__ << endl;
            // Transitions to other states
            bool is_event_detected = true;
            if(is_event_detected)    setState(&States::state2);
        }
        void state2()
        {
            if(isEnteringState())    cout << "Entering ";
            cout << __func__ << endl;
            bool is_exit_detected = true;
            if(is_exit_detected)    setState(nullptr);
        }
};
int main()
{
    States fsm;
    bool is_fsm_running = true;
    while(is_fsm_running)
    {
        is_fsm_running = fsm.update();
    }
    return EXIT_SUCCESS;
}

在 FSM(指向实现状态的派生对象的指针(中存储m_states的唯一目的是在 update(( 中调用 m_state_action,update(( 是指向派生对象方法的指针。相反,我想知道将其(FSM*类型(转换为具有static_cast的国家*是否是一种好的做法?

(static_cast<States*>(this)->*m_state_action)();

行为是否定义良好?(我知道它适用于 mingw 7.30(

另外,作为一个附带问题,用一个作为其子级的类模板化 FSM 看起来有点奇怪(类状态:公共 FSM(......我可以以不同的方式做到这一点吗?

是的,在两个条件下它是合法的:

  1. States必须公开和非虚拟地继承FSM<States>

    您的设计已经需要此使用模式,但最好添加一个static_assert来强制实施此要求。

  2. 该对象实际上是 States 的一个实例。

    即使不是不可能,也很难预防struct BogusStates : FSM<TrueStates> {};

    您至少可以通过为其提供一个protected构造函数来防止任何人直接实例化FSM<States>

这里的问题是,它足够安全吗?

可能的滥用是相当微不足道的:

class FooStates { }
class BarStates : FSM <FooStates> { }

现在,FSM <FooStates>this演员将BarStates*投向FooStates*。一种可能的保护措施是使用 dynamic_cast ,但这需要FSM<>有一个虚拟方法。这是一个运行时检查,但你只需要执行一次。遗憾的是,您无法在 FSM 构造函数中执行此操作,因为此时派生对象States尚未创建。

C++中的模板使用了鸭子打字的想法。因此,在没有任何强制转换的情况下调用State类型的任何函数是安全的。如果此方法不存在,它将无法编译。

有一个代码示例来说明我的意思:https://rextester.com/MPXX23993

相关文章: