1

我有一个子类,它将基类的方法作为线程启动。子类还实现了基类的纯虚方法。然后线程需要在线程中调用子实现版本的纯虚方法,但是线程抛出异常:“调用了纯虚方法”。下面的代码演示了在构造 Child 时会发生什么:

class Base {
  std::thread messageThread;

  virtual void processMessage(std::string msg) = 0;

  static void checkForMessages(Base *c) {
    while(true) {
      std::string msg = "Hello";
      c->processMessage(msg);
    }
  }
};

class Child : public Base {
  Child() {
    messageThread = std::thread(checkForMessages, this);
  }

  void processMessage(std::string msg) {
     std::cout << "Message: " << msg << std::endl;
  }
};

我的理解是 Child 在构造函数完成之前仍然被认为是 Base ,因此线程只能将 processMessage 视为纯虚函数。我可以为 Base 的每个孩子实现 checkForMessages,但这首先违背了拥有 Base 类的目的。

我怎样才能正确地实现这一点?感谢您的帮助!

编辑:演示问题的完整示例,并尝试修复:https ://gist.github.com/4590476

4

3 回答 3

3

您可以std::thread(checkForMessages, this)进入一个单独的start()方法,该方法必须在构造对象后由调用者调用。

于 2013-01-21T22:42:37.113 回答
1

显然有很多方法可以解决这个问题。我的建议是使用两个类:一个用于包装线程,另一个用于实现您的“检查消息”。

lass Base {
  std::thread messageThread;

  virtual void processMessage(std::string msg) = 0;

  static void checkForMessages(Base *c) {
    while(true) {
      std::string msg = "Hello";
      c->processMessage(msg);
    }
  }
};

class Child : public Base {
  Child() {
  }

  void processMessage(std::string msg) {
     std::cout << "Message: " << msg << std::endl;
  }
};

class ThreadWrapper
{
    ThreadWrapper(Base *b)
    {
        messageThread = std::thread(Base::checkForMessages, this);
    }
    ... 
}

....
Child child;
ThreadWrapper tw(&child);

另一个相当明显的选择是在单独的成员函数中启动线程。

如果这些都不是“好”,那么你可能想解释为什么,我们可能会想出一些其他的想法。

以下是“如何从不同的函数启动线程”的几个片段:

类子:公共基础公共:子(){}

    void start(void) { messageThread = std::thread(checkForMessages, this); }


    ~Child() {
        messageThread.join();
    }

……

int main()
{
    Child c;
    c.start();

我还修改了 checkForMessage 以在一段时间后退出。在我的测试用例中工作。

于 2013-01-21T22:46:02.927 回答
1

在线程运行之前,没有什么可以阻止实例Derived被销毁(或至少开始被销毁)。您需要一些智能指针或一些同步。

于 2013-01-21T23:30:28.450 回答