C ++:根据变量将同一对象实例化为多种类型之一

C++: Instantiate same object as one of many types depending on variable

我正在为我设计的 LED 立方体编程。立方体有一个 "pause" 按钮和一个 "play/next" 按钮。除非立方体暂停,否则它将循环播放我为它制作的所有不同效果(动画)。如果按下暂停按钮,立方体将不再在效果之间转换,而是重复当前效果。按 'play/next' 按钮将取消暂停功能并立即前进到下一个效果。

其中一些效果非常复杂,需要在动画帧之间保留大量变量。为了立即轻松销毁所有这些变量(比如按下下一个按钮时),我将当前动画实例化为一个对象,并在效果完成或按下跳过按钮时销毁它。

我正在尝试按如下方式设置我的主循环:

void loop() {
  //create an effect object
  switch(effectIndex){
    case 0:
    EF_GROWFRAME effect;
    break;
    case 1:
    EF_RANDOMFILL effect;
    break;
  }

  bool proceed;

  do{
    //returns false until the effect has completed
    proceed=effect.step();
    //push this cube update and wait for it to display
    cube.update();
    cube.waitForFrame();
  }
  while ((!proceed)&&(!skipflag));
  //skipflag is set true during a timer interrupt if the skip button is freshly pressed
  skipflag=false;
  cube.clearPattern();

  if (play) effectIndex++;
  if (effectIndex=effectCount) effectIndex=0;
}

由于我对 effect 的定义相互矛盾,所以失败了。您可能会明白我要做什么,那么处理这个问题的正确方法是什么?

这是多态性的一个用例。

定义一个基础 class,Animation 定义一个共享接口并让您的各种动画类型从中派生。例如:

class Animation {
public:
    virtual ~Animation() {
        // any generic cleanup shared by all animation types
    }
    virtual bool step() = 0;
};

class AnimationA : public Animation {
public:
    bool step() override {
        // logic for this type of animation
    }
};

class AnimationB : public Animation {
public:
    bool step() override {
        // logic for this type of animation
    }
};

void loop() {
    std::unique_ptr<Animation> effect;

    switch (effectIndex) {
    case 0:
        effect = std::make_unique<AnimationA>();
        break;
    case 1:
        effect = std::make_unique<AnimationB>();
        break;
    }

    //...
}

Live Demo


由于这似乎是一个嵌入式环境,您可以通过将动画播放逻辑分解到一个单独的函数中来避免我第一个示例中的动态内存分配:

void playAnimation(Animation& effect) {
    bool proceed;

    do{
        //returns false until the effect has completed
        proceed=effect.step();
        //push this cube update and wait for it to display
        cube.update();
        cube.waitForFrame();
    } while (!proceed && !skipFlag);
    //skipflag is set true during a timer interrupt if the skip button is freshly pressed
    skipflag=false;
    cube.clearPattern();
}

void loop() {
    switch (effectIndex) {
    case 0:
        {
            AnimationA effect;
            playAnimation(effect);
            break;
        }
    case 1:
        {
            AnimationB effect;
            playAnimation(effect);
            break;
        }
    }

    if (play) effectIndex++;
    if (effectIndex == effectCount) effectIndex=0;
}

Live Demo