
All this is fine if PumpBase has few states. Yet consider the case when 2 developers work on PumpBase, one responsible for customizing the Running state, the other for customizing the Stopped state. The developers should be able to work on the state machine without knowing each other. Yet as I've illustrated above, there can only be one MyPump class and whoever writes that class has to be aware of the MyRunning and MyStopped class and write the react functions accordingly.
I'm not sure whether I understand 100% but it seems if you use the technique above this shouldn't be a problem.
I followed your example/suggestions and wrote the following test program. Conceptually speaking, the PumpBase FSM has 2 states, Idle and Running, the designer of this FSM want to allow customization of these 2 states, which is limited to adding inner states. The customization for the Idle state (MyIdle) could be developed by Bob, while the customization for the Running state (MyRunning) could be developed by Mary and since Bob and Mary are adding inner states to Idle and Running respectively, their code should not depend on each other. However, as my test program shows, MyPump class needs to have knowledge of both MyIdle and MyRunning and provide the implementation for the react functions. This means the 2 points of customization cannot be viewed as separate and independent. If MyPump only customized the Idle state but not the Running state, and a third developer with no access to MyPump's source code will have to customize MyPump to add inner states for the Running state. PumpBase +--> MyPump +--> CustomMyPump I don't mean to say that this will prevent anything from working but I just want to clarify what I was trying to point out. Please correct me if I'm wrong thanks Dave struct EvStart : sc::event< EvStart > {}; struct EvPreIdleStart : sc::event< EvPreIdleStart > {}; struct EvPreRunningStart : sc::event< EvPreRunningStart > {}; class EntryExitDisplayer { ... } //////////////////////////////////////////////////////////////////////////////// // Base FSM //////////////////////////////////////////////////////////////////////////////// struct PreIdle; struct PreRunning; struct PumpBase : sc::state_machine< PumpBase, PreIdle > { virtual sc::result react(PreIdle & preIdle, const EvPreIdleStart & ) const; virtual sc::result react(PreRunning & preRunning, const EvPreRunningStart & ) const; }; struct PreIdle : sc::state<PreIdle, PumpBase>, EntryExitDisplayer { typedef sc::custom_reaction< EvPreIdleStart > reactions; PreIdle(my_context ctx) : my_base(ctx), EntryExitDisplayer("PreIdle") { post_event( boost::intrusive_ptr<EvPreIdleStart>( new EvPreIdleStart() ) ); } sc::result react( const EvPreIdleStart & evt ) { return context< PumpBase >().react( *this, evt ); } }; struct Idle : sc::simple_state< Idle, PumpBase>, EntryExitDisplayer { typedef sc::transition< EvStart, PreRunning > reactions; Idle() : EntryExitDisplayer("Idle") {} }; struct PreRunning : sc::state<PreRunning, PumpBase>, EntryExitDisplayer { typedef sc::custom_reaction< EvPreRunningStart > reactions; PreRunning(my_context ctx) : my_base(ctx), EntryExitDisplayer("PreRunning") { post_event( boost::intrusive_ptr<EvPreRunningStart>( new EvPreRunningStart() ) ); } sc::result react( const EvPreRunningStart & evt ) { return context< PumpBase >().react( *this, evt ); } }; struct Running : sc::simple_state< Running, PumpBase >, EntryExitDisplayer { Running() : EntryExitDisplayer("Running") {} }; sc::result PumpBase::react(PreIdle & preIdle, const EvPreIdleStart & ) const { return preIdle.transit< Idle >(); } sc::result PumpBase::react(PreRunning & preRunning, const EvPreRunningStart & ) const { return preRunning.transit< Running >(); } /////////////////////////////////////////////////////////////////////////////// // Custom FSM /////////////////////////////////////////////////////////////////////////////// struct MyIdle : sc::simple_state< MyIdle, PumpBase >, EntryExitDisplayer { typedef sc::transition< EvStart, PreRunning > reactions; MyIdle() : EntryExitDisplayer("MyIdle") {} }; struct MyRunning : sc::simple_state< MyRunning, PumpBase >, EntryExitDisplayer { MyRunning() : EntryExitDisplayer("MyRunning") {} }; struct MyPump : PumpBase { virtual sc::result react( PreIdle & preIdle, const EvPreIdleStart & ) const { return preIdle.transit< MyIdle >(); } virtual sc::result react( PreRunning & preRunning, const EvPreRunningStart & ) const { return preRunning.transit< MyRunning >(); } }; int main(int argc, char** argv) { MyPump p; p.initiate(); std::cout << "External event EvStart posted...\n"; p.process_event(EvStart()); sleep(5); return 0; }