2011-09-12 58 views
5

重复的:"pure virtual method called" when implementing a boost::thread wrapper interface提升线程破坏多态性

我试图创建一个使用升压线程的线程更多的面向对象版本。

所以我创建了一个Thread类:

class Thread { 
public: 
    Thread() {} 
    virtual ~Thread() { thisThread->join(); } 

    void start() { thisThread = new boost::thread(&Thread::run, this); } 

    virtual void run() {}; 

private: 
    boost::thread *thisThread; 
}; 

这个类中创建启动线程() 这样的:

thisThread = new boost::thread(&Thread::run, this);

的问题是,当我创建一个类,覆盖run()方法,从Thread的run()方法是由线程调用而不是新的run()方法

,比如我有继承Thread类:

class CmdWorker: public Thread { 
public: 
    CmdWorker() : Thread() {} 
    virtual ~CmdWorker() {} 

    void run() { /* deosn't get called by the thread */ } 
}; 

当我做

Thread *thread = new CmdWorker(); 
thread.start(); //---> calls run() from Thread instead of run() from CmdWorker 

但为了更加清晰:

thread.run(); calls the correct run from CmdWorker, (run() is virtual from Runnable) 

任何想法,为什么出现这种情况或如何修复?

注: 我创建了一个函数(即具有无关Thread类)

void callRun(Thread* thread) { 
    thread->run(); 
} 

,改变了线程创建于:

thisThread = new boost::thread(callRun, this); 

当调试我注意到thread指针指向Thread类型的对象而不是CmdWorker

编辑:

测试用例代码为:http://ideone.com/fqMLFhttp://ideone.com/Tmva1

对象似乎切片(但是这是奇怪的,因为使用指针)

没能提振添加到它

+0

这个问题我不清楚! – Nawaz

+1

代码不足。我看不出你会如何使用这种构造。 –

+2

FYI'std :: thread'即将到达。无论如何,boost :: thread'究竟有什么问题? – spraff

回答

1

这样做&Thread::Run在非虚函数上,您迫使从Thread派生的任何类使用Thread基类中指定的函数。尝试让Thread ::运行一个虚拟的void,看看是否解决了你的问题。

+1

运行是从Runnable虚拟的 – Ha11owed

+0

但不是来自线程。 – Michael

+3

@Michael:在C++中,只要成员函数签名匹配(他们在这种情况下),'virtual'就会从基类继承。将'Thread :: run'声明为'virtual'将是多余的。 – ildjarn

3

调试时我注意到,螺纹指针指向型螺纹,而不是CmdWorker的 对象

也许CmdWorker对象被切片(即,由值复制)到一个Thread对象某处你的代码?

你是否得到了与最小测试用例相同的行为?

+0

是的我得到了与测试案例相同的行为 – Ha11owed

2

从阅读您的更新,您在主线程中调用delete,而线程在另一个线程中启动。根据析构函数和run调用之间的竞争,这将:

  1. 崩溃开始之前,因为虚函数表被完全破坏
  2. 调用的线程运行::(这是纯虚拟的,采用了纯虚拟的thunk崩溃)
  3. 调用正确的函数,这是派生类的run()

如果添加了调用sleep(1)你打电话开始后,但你叫delete之前,你会发现它起作用了你期望的。

+0

我简化了示例并删除了任何锁+检查。 也在析构函数中我做了一个join(),所以它等待线程完成。 正如我之前提到的,run()从线程被调用。 – Ha11owed

+3

@ Ha11owed如果在'Thread'的析构函数中添加一个连接,那么在调用连接时,大部分派生类已经被销毁,并且它的vtable条目不再存在。 –

+0

我现在明白了 没有注意到 – Ha11owed