2016-11-23 87 views
4

在C++类中处理状态的最有效和最现代的方式是什么? 目前我正在使用多个布尔,但越多我说我更难以维护。例如,如果我有一个名为VideoPlayer的类,并且它有四个定义不同状态的布尔值。如果我们为每个布尔添加set方法,我们需要取消设置所有其他布尔。在C++类中处理多个状态

class VideoPlayer 
{ 

public: 
    void play() 
    { 
     play_ = true; 
     pause_ = false; 
     stop_ = false; 
     reset_ = false; 
    } 

    void stop() 
    { 
     stop_ = true; 
     play_ = false; 
     pause_ = false; 
     reset_ = false; 
    } 

private: 
    bool play_; 
    bool pause_; 
    bool stop_; 
    bool reset_; 
}; 
+0

也许一个小的有限状态机将是适当的。 –

+3

看起来像枚举可能在这里做的工作。 – sjwarner

+0

如果您使用的是C++ 11,请改用'enum class'。 – Dai

回答

8

您的设计从它易于遭受是在一个糟糕的状态(例如,如果什么都stop_play_都是true

您应该使用enum定义仅1罐set of finite-states

C++的enum类型有点不同于Swift,Java和C#的enum:它们没有显示出来,并且隐含转换更宽容 - 表现得有点像simi larly到#define

C++ 11增加了enum class这与C#的enum非常相似。但是,没有内置的功能类似于Java或Swift的enum的灵活性。

你会想是这样的:

enum class PlayerState { 
    Stopped, 
    Playing, 
    Paused 
} 

如果Reset不是一个国家,而是一个动词,那么它不应该是在enum定义。

class VideoPlayer { 
private: 
    PlayerState state; 
public: 
    VideoPlayer() : 
     state(PlayerState::Stopped) 
    { 

    } 

    void play() { 

     switch(this->state) { 
      case PlayerState::Stopped: 
       // start video here, only change `state` when complete. 
       // you might want to add a "BeginPlaying" (e.g. `LoadingFileFromDisk`) state value too. 
       this->state = PlayerState.Playing; 
       break; 
      case PlayerState::Playing: 
       throw VideoPlayerStateExeception("Already playing"); 
      case PlayerState::Paused: 
       this->resume(); 
       break; 
     } 
    } 


} 
+0

这种方法可以同时处于多个状态吗?当你用bools自然地获得它。 – sabotage3d

+0

@ sabotage3d不,这是故意的。请阅读关于有限状态机的链接维基百科文章, – Dai

+0

我非常了解FSM和HFSM。我最初的问题是处理多个国家。我将修改我的示例以使其更清楚。 – sabotage3d

0

我会用C++ 17的std::variant。数据将成为各国的类型。

struct Playing { 
    float time_from_start; 
}; 

struct Paused { 
    float time_from_start; 
}; 

struct Stopped {}; 

struct MediaPlayer { 
    std::variant< 
     Playing, 
     Paused, 
     Stopped 
    > state; 

    void play() { 
     state = Playing{}; 
    } 

    void pause() { 
     state.visit([&](auto&& s){ 
      using S = std::decay_t<decltype(s)>; 

      float time = 0; 

      if constexpr (std::is_same_v<S, Playing>) { 
       time = s.time_from_start; 
      } 

      state = Paused{time}; 
     }); 
    } 
}; 

甚至可以添加其他一些有用的状态:

struct ABLoop { 
    float a, b, time_from_a; 
};