将"this"从父类方法转换为子类方法是一种好的做法吗?
Is casting "this" from a parent class method to a child a good practice?
我正在实现一个非常基本的基类来运行有限状态机。这是我所做的...
/**
* @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(......我可以以不同的方式做到这一点吗?
是的,在两个条件下它是合法的:
-
States
必须公开和非虚拟地继承FSM<States>
。您的设计已经需要此使用模式,但最好添加一个
static_assert
来强制实施此要求。 -
该对象实际上是
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
- 有没有一种方法可以在编译时获得作用域类名
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 使用类在C++中存储和列出变量/方法是否是一种好的做法
- 类中一种方法的部分专用化
- 构造函数是否有一种现代C++方法来了解其'container'类?
- 有没有一种快速的方法可以将类的所有静态成员归零?
- 有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
- 在类方法中使用 "this" 指针是否是一种好的做法?
- 抽象类/接口中的空方法是否被认为是一种好的做法?
- 将"this"从父类方法转换为子类方法是一种好的做法吗?
- C 编译器未检查模板类中是否存在一种方法
- 一种安全、符合标准的方法,使类模板专用化仅在实例化时才无法使用"static_assert"进行编译
- 是否有一种方法可以始终通过值(制作副本)而不是在使用类成员函数时通过参考来传递
- 按类型为继承的类制作一种切换案例
- 一种创建将字符串常量返回给枚举的类的廉价方法,反之亦然
- C++是否提供了一种在没有范围解析运算符的情况下访问类中的类的方法?
- (C )正在创建专门用于处理所有其他自定义对象的类/对象一种处理项目的正确方法
- 在我的C++应用程序中定义IHaveVirtualDestructor基类是一种好的做法吗
- 为已经存在的注册表类使用包装类是一种好方法吗?
- XML类描述到c++类描述:一种设计模式