0

我是新来的回调函数。我写了一个Timer类。它将回调函数存储在其中,并在它们各自的周期后回调它们。

定时器.h

#ifndef UTILITY_CLASSES__TIMER_H
#define UTILITY_CLASSES__TIMER_H

#include <stdint.h>
#include <list>
#include <Windows.h>

class Timer
{
    public:
        static uint64_t LAST_TIMER_ID;
        uint64_t TimerId;
        uint64_t KillId;
        typedef void (*TimerCallBackFunction) (DWORD, uint64_t);

        Timer(UINT Period, TimerCallBackFunction CbFunction);
        ~Timer();

    protected:
        class TimerInfo
        {
            public:
                TimerInfo(TimerCallBackFunction Cbf, uint64_t Tid, uint64_t Kid)
                    : Callback(Cbf), TimerId(Tid), KillId(Kid) {}
                TimerCallBackFunction Callback;
                uint64_t TimerId;
                uint64_t KillId;
        };

        static VOID CALLBACK TimerProc( _In_  HWND hwnd,
                                        _In_  UINT uMsg,
                                        _In_  UINT_PTR idEvent,
                                        _In_  DWORD dwTime);

        static std::list<TimerInfo> Timers;
};

#endif  // UTILITY_CLASSES__TIMER_H

定时器.cpp

#include "Timer.h"

#include <Windows.h>

uint64_t Timer::LAST_TIMER_ID = 0;

Timer::Timer(UINT Period, TimerCallBackFunction CbFunction)
{
    TimerId = ++LAST_TIMER_ID;
    KillId = SetTimer(NULL, TimerId, Period, Timer::TimerProc);
    if (KillId == NULL)
    {
        LAST_TIMER_ID--;    // roll back
        TimerId = 0;
    } 
    else
    {
        Timers.push_back(TimerInfo(CbFunction, TimerId, KillId));
    }
}

Timer::~Timer()
{
    for (std::list<TimerInfo>::const_iterator it=Timers.begin(); it!=Timers.end(); ++it)
    {
        if (it->TimerId == TimerId)
        {
            Timers.erase(it);
            break;
        }
    }
}

VOID CALLBACK Timer::TimerProc( _In_ HWND hwnd,
                                _In_ UINT uMsg,
                                _In_ UINT_PTR idEvent,
                                _In_ DWORD dwTime)
{
    for (std::list<TimerInfo>::const_iterator it=Timers.begin(); it!=Timers.end(); ++it)
    {
        if (it->TimerId == idEvent)
        {
            it->Callback(dwTime, it->TimerId);
            break;
        }
    }
}

主文件

#include <Windows.h>
#include "Timer.h"

class MyClass
{
    public:
        void CallMe(DWORD Time, uint64_t TimerId)
        {
            MessageBoxW(NULL, L"Callback function is called!",
                        L"Notification", MB_ICONINFORMATION);
        }
};

int APIENTRY wWinMain(  _In_        HINSTANCE   hInstance,
                        _In_opt_    HINSTANCE   hPrevInstance,
                        _In_        LPTSTR      lpCmdLine,
                        _In_        int         nCmdShow)
{
    // ...

    MyClass MyObject;
    Timer TimerObject(10000, MyObject.CallMe);  // Line 114

    //...
    return 0;
}

编译此代码时收到此错误消息:

第 114 行
错误 C3867:
'MyClass::CallMe':函数调用缺少参数列表;使用 '&MyClass::CallMe' 创建指向成员的指针

MyObject.CallMe当我更改到第 114 行&MyClass::CallMe或在第 114行时,我无法运行我的代码&MyObject.CallMe

我在我的代码中做错了什么?


IDE:Microsoft Visual Studio 2012
文档:SetTimerTimerProc

4

2 回答 2

2
typedef void (*TimerCallBackFunction) (DWORD, uint64_t);

为指向自由函数的指针声明了一个 typedef,这些不能用于指向成员函数。您需要一个指向成员函数的指针:

typedef void (MyClass::*TimerCallBackFunction) (DWORD, uint64_t);

您需要MyClass在创建 typedef 之前转发声明,并且还需要按照错误消息中的说明进行操作:

Timer TimerObject(10000, &MyObject::CallMe);
                      // ^^^^^^^^^^^^^^^^^

推荐阅读:C++ FAQ Lite 中成员函数的指针部分。

于 2013-07-28T14:59:40.213 回答
1

我会使用std::function而不是函数指针,然后使用std::bind占位符:

将 typedef 更改为

    typedef std::function<void (DWORD, uint64_t)> TimerCallBackFunction;

并且在 中WinMain(),绑定实例的一个std::function,然后将使用替换占位符的两个参数调用该实例。CallMe()MyObject

MyClass MyObject;
Timer TimerObject(10000, std::bind(&MyClass::CallMe,
                                   MyObject,
                                   std::placeholders::_1,
                                   std::placeholders::_2));
于 2013-07-28T14:59:44.513 回答