从void *转换时的C ++多态性问题

时间:2013-02-18 11:51:13

标签: c++ windows multithreading inheritance polymorphism

我有以下代码:

#include <windows.h>
#include <iostream>

static DWORD __stdcall startThread(void *);

class BaseClass {
private:

    void threadLoop() {
        // stuff ...
        std::cout << someStuff() << std::endl;
        // stuff ...
    }
protected:
    HANDLE handle;
    virtual int someStuff() {
        return 1;
    }
public:
    friend DWORD __stdcall startThread(void *);

    BaseClass() {
        handle = 0;
    };

    void start() {
        handle = CreateThread(NULL, 0, startThread, this, 0, NULL);
    }

    ~BaseClass() {
        if(handle != 0) {
            WaitForSingleObject(handle, INFINITE);
            CloseHandle(handle);
        }
    }
    // stuff
};

static DWORD __stdcall startThread(void *obj_) {
    BaseClass *obj = static_cast<BaseClass *>(obj_);

    obj->threadLoop();
    return 0;
}

class DerivedClass : public BaseClass {
public:
    virtual int someStuff() {
        return 2;
    };
};

int main() {
    BaseClass base;
    base.start();
    DerivedClass derived;
    derived.start();
}

每个实例使用WINAPI和帮助函数startThread创建一个线程,该函数将调用委托给创建线程的对象的方法threadLoop。现在的问题是threadLoop调用了另一个虚方法,但如果我用其他实现的虚方法创建一个派生类,那么多态似乎不起作用。

为什么呢?我该如何解决这个问题?

编辑:我更新了代码,因此线程无法在构造函数中启动。

2 个答案:

答案 0 :(得分:6)

你在完成构建之前就开始了 派生对象。这是未定义的行为(因为你会 你可能正在访问新主题中的对象 仍然在创建线程中执行代码)。你必须这样做 单独的构造和启动线程。

编辑:

处理此类问题的一种方法:

class Threadable
{
public:
    virtual Threadable() {}
    virtual run() = 0;
};

DWORD __stdcall startThread( void* object )
{
    static_cast<Threadable*>( object )->run();
}

class Thread
{
    std::auto_ptr<Threadable> myThread;
    HANDLE myHandle;
public:
    Thread( std::auto_ptr<Threadable> thread )
        : myThread( thread )
        , myHandle( CreateThread( NULL, 0, startThread, myThread.get(), 0, NULL ) )
    {
    }
    ~Thread()
    {
        if ( myHandle != NULL ) {
            WaitForSingleObject( myHandle, INFINITE );
            CloseHandle( myHandle );
        }
    }
};

然后让您的BaseClassDerivedClass派生自 Threadable,并将其调用为:

Thread base( std::auto_ptr<Threadable>( new BaseClass ) );
Thread derived( std::auto_ptr<Threadable>( new DerivedClass ) );

这并不完美(我不喜欢或多或少无限制的等待 析构函数),但它应该足以开始。 (模 上面代码中的任何拼写错误 - 我都没有测试过。)

答案 1 :(得分:1)

您的代码存在一些问题,例如您在构造对象时正在创建和运行线程。这绝对是一个糟糕的设计。

一个简洁的设计是将线程功能封装在一个名为thread的抽象类中,然后从中派生,覆盖run方法,例如:

class thread : public noncopyable
{
protected:
    HANDLE m_hthread;
    unsigned long m_id;
private:
    static unsigned long __stdcall start(void* args)
    {
        static_cast<thread*>(args)->run();
        return 0;
    }
public:
    thread();
    virtual ~thread();
    virtual bool start()
    {
        if ( m_hthread != nullptr && isrunning(m_hthread) ) 
        {
           throw std::logic_error("Cannot start thread, as it is already running.");
        }
    m_hthread = ::CreateThread(NULL, 0, start, this, 0, &m_id);
    return m_hthread != nullptr;
    }
    unsigned long get_id() const;
    virtual unsigned long wait();
protected:
    virtual void run() = 0;
};

从中衍生出来:

class worker : public thread
{
  protected:
      virtual void run() override;
};

你会用它作为:

worker workerObject;
workerObject.start();

//do other works here
//maybe create few more threads;

workerObject.wait(); //wait for worker to complete!