【问题标题】:c++ Hold instructions for a later timec++ 稍后保留指令
【发布时间】:2020-10-17 18:27:06
【问题描述】:

我正在尝试设计一个 UIDraw 方法。我想在主要的 Draw 方法中声明要绘制哪些 UI 元素,然后在代码的后面有一个单独的 UIDraw 方法。所以我需要一种方法来存储要在这个新函数中执行的指令。我希望这是有道理的。 像这样的:

        Draw();
        DrawUI();

但是说在 Draw() 函数中要绘制什么 UI。 关于如何解决这个问题的任何想法?

【问题讨论】:

  • StackOverflow 仅针对特定问题。请拨打tour 了解您可以在这里询问的内容。
  • “关于如何解决这个问题的任何想法?” 是否可以为特定的 UI 元素使用可选参数?
  • @NikitaDemodov 这个问题对我来说够具体了吗?
  • 可能会创建一个 std::functions 的 std::vector,然后遍历该向量并调用所有函数?

标签: c++ user-interface methods draw instructions


【解决方案1】:

有很多方法可以解决这个问题,具体取决于您究竟需要什么。 OO 世界中流行的一种方法是所谓的Command Pattern(类似的方法存在于其他编程范例中,它们只是名称不同,或者被认为非常明显,甚至根本没有特定的名称)。

基本思路是这样的:你想执行某个命令,但是你想执行命令的时间和你决定执行什么命令的时间是不同的。所以解决这个问题的方法是简单地创建一个包含执行命令所需信息的对象,将该对象传递到决定何时执行的地方,然后该代码可以随心所欲地运行命令。

这是 C++ 中的样机(注意:实际上并未编译此代码,可能包含小错误 - 只是为了传达这个想法)。

#include <memory>
#include <vector>

/// this is an abstract class that gives us an interface to use
class DrawCommand {
  public:
  virtual void Draw() = 0;
};

/// one kind of thing you might want to draw
class DrawTree : public DrawCommand {
  public:
  void Draw() override {
     // tree drawing code
  }
};

/// another kind of thing you might want to draw
class DrawCat : public DrawCommand {
  public:
  void Draw() override {
    // cat drawing code
  }
};

/// we can even come up with ways to combine these in interesting ways
class DrawABunchOfThings : public DrawCommand {
  std::vector<std::unique_ptr<DrawCommand>> things;
  public:
  DrawABunchOfThings(std::vector<std::unique_ptr<DrawCommand>> things)
    : things{std::move(things)}
  {}

  void Draw() override {
    for(auto &thing : things) {
      thing->Draw();
    }
  }
};

/// this is where we decide what we will draw
std::unique_ptr<DrawCommand> PrepareDraw() {
  if(someCondition) {
    // just a cat
    return std::make_unique<DrawCat>();
  } else if(someOtherCondition) {
    // just a tree
    return std::make_unique<DrawTree>();
  } else {
    // forest with a cat hidden inside
    return std::make_unique<DrawABunchOfThings>(
      std::vector<std::unique_ptr<DrawCommand>>{
        std::make_unique<DrawTree>(),
        std::make_unique<DrawTree>(),
        std::make_unique<DrawCat>()
        std::make_unique<DrawTree>(),
      }
    );
  }
}

/// this is where we will do the actual drawing
/// note that any arbitrary amount of code can go between
/// PrepareDraw and ExecuteDraw
void ExecuteDraw(DrawCommand &command) {
  // this can of course have a bunch of elaborate
  // code here as well -- also, DrawCommand::Draw might
  // take extra parameters here, like 2D or 3D transforms,
  // time since we last drew something, or whatever
  command.Draw();
}

注意,如果你只需要一个方法,C++ 已经有 std::function 的形式,所以你可以说 using DrawCommand = std::function&lt;void()&gt;; 并完成它,这也将立即允许你使用它使用 lambda:

int nTimes = 10;
DrawCommand drawNTimesCommand = [nTimes]() {
  for(int i = 0; i < nTimes; ++i) {
    // draw something
  }
};

// --- any code you like here ---

// actually execute the draw command
drawNTimesCommand();

【讨论】:

  • 非常感谢。我是 C++ 的新手(习惯于统一),所以这对我来说是全新的。但这教会了我很多!非常感谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 2018-11-03
  • 2011-06-27
  • 1970-01-01
相关资源
最近更新 更多