2013-01-15 33 views
2

可能重複:
function pointer for a member function傳遞一個方法指針起作用

我有一個問題,在一個類中,我有這樣的方法:virtual void start(void *(*ptr)(void*), void *);
在另外一個,我想打電話從這個方法開始:void *Room::run(void *p)

於是,我就這樣做:thread->start(&Room::run, 0);但是編譯器不想要它,因爲:cannot convert parameter 1 from 'void *(__thiscall Room::*)(void *)' to 'void *(__cdecl *)(void *)'

我怎樣才能解決這個問題?模板?還是有更明顯的解決方案?
謝謝!

P.S:只是爲了確切,我需要它來製作線程(http://linux.die.net/man/3/pthread_create)。

+0

我編輯了你的標題。請參閱[「應該在其標題中包含」標籤「?」](http://meta.stackexchange.com/questions/19190/),其中的共識是「不,他們不應該」。 – Default

+1

是運行一個靜態方法嗎?如果沒有,你不能像那樣使用它。實例方法隱含地與實例('* this'指針)相關聯 –

+0

您可以使用正確的簽名創建一個非成員函數,然後通過它。 –

回答

3

在C++中,指向(獨立)函數和指向方法的指針是不能混合的完全不同的野獸。

如果你想一個指針到成員函數傳遞給需要一個指針到功能的API,那麼典型的解決方案是使用小包裝函數:

class Room { 
public: 
    void run(); 
    // other members omitted 

    // wrapper function 
    static void* run_wrapper(void* p) 
    { 
    static_cast<Room*>(p)->run(); 
    return NULL; 
    } 
}; 

你使用這樣的:

thread->start(Room::run_wrapper, myRoomPointer); 
+0

您不應該傳遞對象myRoom,而是指向start方法的指針以符合static_cast。 – harper

+0

@harper:我認爲'myRoom'是一個指針,但沒有說清楚。 –

+0

這需要'&Room :: run_wrapper'。成員函數並不像自由函數那樣隱含地轉換爲他們的地址。 –

0

我會強烈建議不要鑄造函數指針void *指針,在C++中也可能有C爲好,大小可能會有所不同。

總的來說,你的解決方案不是非常的C++。無可否認,使用c庫會使它有點棘手。下面是我用我的當前項目的方法: -

class ThreadBase 
{ 
public: 
    ThreadBase() 
    { 
    } 

    virtual ~ThreadBase() 
    { 
    // TODO - inform thread to stop, using a message or a signal or something 
    // and then wait for the thread to terminate 
    void 
     *return_value = 0; 

    pthread_join (m_thread_handle, &return_value); 
    } 

    void Run() 
    { 
    if (pthread_create (&m_thread_handle, 0, ThreadFunction, this)) 
    { 
     // error - throw an exception or something 
    } 
    } 

private: 
    static void *ThreadFunction (void *param) 
    { 
    ThreadBase 
     *thread = static_cast <ThreadBase *> (param); 

    thread->Main(); 

    return 0; 
    } 

    virtual void Main() = 0; 

private: 
    pthread_t 
    m_thread_handle; 
}; 

,然後從ThreadBase實施特定版本獲得:

class SomeThread : public ThreadBase 
{ 
private: 
    void Main() 
    { 
    // do something 
    } 
}; 

你可能想改變Main返回的退出代碼,並通過那從線程回來。如果它處於無限循環(例如,如果它是一個偵聽器,消費某種類型的消息),則需要一種方法使Main退出。

+0

謝謝你的解決方案,我會研究它,但現在我會保留另一個,因爲我的時間很短。 – Florian

+0

@弗洛裏安:看着另一個,他們實際上是一樣的,這一個是更多的面向對象。 – Skizz

+0

不好意思,但是這種內在的破壞:首先,你不能在基類的構造函數中啓動線程,因爲那時實際類型是ThreadBase,導致調用一個純虛函數。其次,在析構函數中停止線程就像在fstream的析構函數中刪除一個文件一樣。最後,隱式轉換爲void *與reinterpret_cast配對。這應該是一個static_cast來代替。如果你不想要上面的簡單解決方案,可以考慮使用一個C++線程庫,比如Boost's或者內置的C++ 11。 –