【问题标题】:Best approach for casting pointer to method from derived to base class将指针从派生类转换为基类的最佳方法
【发布时间】:2019-05-23 15:59:13
【问题描述】:

我们有一个旨在通用的基类 ByteCode。 ByteCode 的子级应该编写如下形式的方法:

void m();

ByteCode 类应该有一个方法定义:

typedef void (ByteCode::*Method)();

为了执行字节码,我们有:

void exec() {
  while (true) {
    uint16_t opcode = getOpcode();
    Method m = opcodes[opcode];
    this->*m();
  }
}

在一堂课上这样做是没有问题的。但是我们在基类中有泛型代码,而派生有数组:

class MyByteCodeEngine : public ByteCode {
private:
  static Method opcodes[65536];

  void m1() {}
  void m2() {}
  void m3() {}
};

Method MyByteCodeEngine ::opcodes[65536] = {
  MyByteCodeEngine::m1,
  MyByteCodeEngine::m2,
  MyByteCodeEngine::m3
}

问题是这些方法不是基类,它们是派生的。但是我们唯一拥有的实例是派生的,我们不想招致虚拟的开销,我们只想强制转换并使其工作,但编译器正在捕捉每一个技巧。如果它只是信任我们:

Method MyByteCodeEngine ::opcodes[65536] = {
  (Method)MyByteCodeEngine::m1,
  (Method)MyByteCodeEngine::m2,
  (Method)MyByteCodeEngine::m3
}

我们可以通过消除 ByteCode 类来解决这个问题,但这会迫使我们在任何有字节码解释器时重复代码。关于如何欺骗 C++ 干净地接受这一点的任何建议?

【问题讨论】:

  • 我会使用 std::vector<std::function<void ()>> 并使用捕获 this 的 lambdas 来初始化它们。

标签: c++ inheritance member-function-pointers pointer-to-member


【解决方案1】:

您可以使用Curiously recurring template pattern 以便基类知道成员函数的类型。

template<class T>
struct ByteCode {
  typedef void (T::* Method)();

  void exec() {
    while (true) {
      uint16_t opcode = getOpcode();
      Method m = T::opcodes[opcode];
      static_cast<T*>(this)->*m();
    }
  }
};

class MyByteCodeEngine : public ByteCode<MyByteCodeEngine > {
  private:
    static Method opcodes[65536];

    void m1() {}
    void m2() {}
    void m3() {}
};

MyByteCodeEngine::Method MyByteCodeEngine ::opcodes[65536] = {
  &MyByteCodeEngine::m1,
  &MyByteCodeEngine::m2,
  &MyByteCodeEngine::m3
}

【讨论】:

  • 我也想过。我相信将 CRTP 与我在 OP 的评论中的提案结合使用将是最好的和最安全的方法。
  • 当然。这就是 CRTP 的用途。
  • @πάνταῥεῖ 不知道,std::function 可能有点沉重。虽然我相信常见的实现对简单的函数指针有优化——不确定这是否也适用于指向成员的指针。向量是另一个不必要的动态分配(虽然我会考虑std::array
  • @Light 好吧,开销当然是一个很好的反对理由。
  • 也想知道是否真的需要继承。只是有一个ByteCodeExecuter&lt;T&gt; 吗?但它可能是真正的 *ByteCodeEngine 类型具有其他需要继承的功能和东西
猜你喜欢
  • 2013-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
  • 2016-10-10
相关资源
最近更新 更多