[C++]傳遞Class Member function pointer至其他Class

困擾已久的傳遞Class的Member function到其他class的問題,在今天仔細參詳了半天高手的code以後,終於把之前的疑惑解決了。

原本都知道要用第三個class來處理這問題,但由於一直搞不懂第三個要怎麼做,所以就一直寫不出來。

目前參考的方法是使用一個Base class來當做傳遞Function pointer的介面,然後一個Template class來讓內層使用的class來使用function pointer,也避開兩個互相參照的class的交互參照之問題。

處理方式如下:
Class Processer (底下稱CP)有工作要麻煩 Class Thread (底下稱CT)處理,但是為了讓Main thread不要卡住,所以CT是另外開一個Thread來處理CP要求的工作。
然而當CT在處理工作時如遇到了例外,並無法立即讓CP知道目前的狀況,所以就需要讓CP開個管道(Function Pointer)來讓CT可以在遇到問題時,回來告知CP。

原本是打算用PostMessage()來達成這樣的需求,但是CT所在的dll可能會移植到別的平台上,所以如果使用PostMessage()來做的話,那麼在移植上,還需要去針對不同平台處理。

但是此時的需求只是要把CT遇到的狀況告知給CP,並由CP來告知使用者而已,所以不會造成CT的程序block,所以這邊就採用Class的 callback方式處理。(如果會發生blocking的話,那還是只能用Windows Message的方式處理會比較好處理,不然Thread也是可以。)

底下範例使用
Class CallBackBase:
class CCallBackBase
{
    public:
        CCallBackBase(){};
        ~CCallBackBase(){};

        virtual bool Execute(void *Param) const = 0;
};




Template Class:
template < class cTarClass >
class CTestCallBack : public CCallBackBase
{
    public:
        typedef bool (cTarClass::*LPFUNC)(void *Param);

    protected:
        cTarClass *m_pTarClass;
        LPFUNC m_pTarFunc;

    public:
        CTestCallBack() {
            m_pTarClass = NULL;
        };
        ~CTestCallBack() {};

        void SetCallBack(cTarClass *cTarClassPtr, LPFUNC pFuncPtr){
            m_pTarClass = cTarClassPtr;
            m_pTarFunc = pFuncPtr;
        };

        virtual bool Execute(void *Param) const        //Execute的參數要與function pointer一致是因為操作者是使用此介面來使用function pointer
        {
            if (m_pTarClass)
            {
                return (m_pTarClass->*m_pTarFunc)(Param);
            }else{
                ::printf("ERROR: The call back funciton is not set!!");
            }
            return false;
        };
};


Class Thread:
class CProcessThread
{
    protected:    
        CCallBackBase *m_pCallBack;
        HANDLE m_hThread;

    public:
        CProcessThread(){
            m_pCallBack = NULL;
            m_hThread = NULL;
        };

        ~CProcessThread(){
            if ( m_hThread != NULL )    {
                DWORD dwExitCode = 0;
                ::TerminateThread(this->m_hThread, dwExitCode);

                HANDLE hThread = this->m_hThread;
                this->m_hThread = NULL;
                ::CloseHandle(hThread);
            }
        };

        void StartProcessThread(void)
        {
            this->m_hThread = CreateThread( NULL, 0, ProcessThread, (LPVOID)this, 0, NULL);
        };

        void SetCallBack(CCallBackBase *pCallBack){
            m_pCallBack = pCallBack;
        };

    protected:
        static DWORD WINAPI ProcessThread(LPVOID lpParam)
        {
            CProcessThread *pcmxProcessThread = (CProcessThread*) lpParam;

            return pcmxProcessThread->ProcessFunc();
        };

        DWORD ProcessFunc(void)
        {
            //Set callback data to upper class
            m_pCallBack->Execute((void*) "This message is pass from ProcessThread::ProcessFunc() in Thread!!\n");

            if ( m_hThread != NULL )    {
                DWORD dwExitCode = 0;
                ::TerminateThread(this->m_hThread, dwExitCode);

                HANDLE hThread = this->m_hThread;
                this->m_hThread = NULL;
                
                ::CloseHandle(hThread);
            }

            return 0;
        };
};



Class Process:
class CProcess
{
    protected:
        CTestCallBack<CProcess> m_CallBack;
        CProcessThread m_ProcessThread;

    public:
        CProcess() {
            m_CallBack.SetCallBack(this, &CProcess::CallBackShower);
            m_ProcessThread.SetCallBack(&m_CallBack);
        };
        ~CProcess() {};

        void StartProcess(void)
        {
            m_ProcessThread.StartProcessThread();
        };

        bool CallBackShower(void *Param)
        {
            char szMsg[512];
            strcpy(szMsg, (char*)Param);

            ::printf("The Pass message from call back is \nMsg = %s", szMsg);

            return true;
        };

};



Main program:
int _tmain(int argc, char* argv[])
{
    CProcess Process;

    Process.StartProcess();

    system("pause");
    return 0;
}


執行結果:



程式碼亂跑的問題再另外找解@@

No comments:

Post a Comment

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...