Класс обслуживания данных через обратные вызовы - PullRequest
2 голосов
/ 17 мая 2019

Недавно я вернулся к Visual C ++, программируя на C, где обратные вызовы намного проще.

У меня есть одноэлементный класс, который управляет 0 .. * подключенными устройствами. Моя идея состоит в том, чтобы создать функцию в этом классе, которая будет перебирать множество подключенных устройств и опубликуйте его с помощью обратного вызова для того, что может потребоваться.

, например

Singleton class

typedef void (CALLBACK * PortListCallback_t)(ptrConstCComPortInfo_t);
.
.
.

void CCommsMgr::listPorts(PortListCallback_t cb)
{
    PortInfoSetConstIter_t i;
    for (i = m_setPorts.begin(); i != m_setPorts.end(); i++)
    {
        cb(*i);
    }
}

В первом случае потребителем является диалоговый класс MFC, который отлично работает, если его обратный вызов является статическим. Однако, чтобы получить доступ к данным / функциям члена диалогового класса, мне нужно передать «this» в синглтон-класс и отразить его обратно.

1010 *, например *

Singleton class

typedef void (CALLBACK * PortListCallback_t)(void *, ptrConstCComPortInfo_t);
.
.
.

void CCommsMgr::listPorts(void *pObj, PortListCallback_t cb)
{
    PortInfoSetConstIter_t i;
    for (i = m_setPorts.begin(); i != m_setPorts.end(); i++)
    {
        cb(pObj, *i);
    }
}


Dialog Class

static void CALLBACK getPorts(void *obj, ptrConstCComPortInfo_t port);
.
.
.

void CALLBACK CMFC_iTFTPDlg::getPorts(void *obj, ptrConstCComPortInfo_t port)
{
   CMFC_iTFTPDlg *pThis = (CMFC_iTFTPDlg*)obj;
   // do something with it
}

Мой вопрос - есть ли лучший способ сделать это? Статические функции ощущаются как клудж, и я не хочу, чтобы класс Singleton был ограничен тем, как его можно использовать. Если я уберу статику на getPorts, она не скомпилируется. Повторюсь, класс Singleton не должен знать своего потребителя.

1 Ответ

0 голосов
/ 17 мая 2019

С помощью превосходных советов от WhozCraig я пришел к следующему:

#include <functional> // std::function, std::bind, std::placeholders
#include <iostream>
#include <vector>

class ConstCComPortInfo {};

using ptrConstCComPortInfo_t = ConstCComPortInfo*;
using callback_t = void(void*, ptrConstCComPortInfo_t);
using function_t = std::function<callback_t>;

// an example class with a member function to call
class foo {
public:
    foo(const std::string& name) : instance_name(name) {}

    void bar(void* something, ptrConstCComPortInfo_t c) {
        std::cout << "foo::bar(" << instance_name << ") called\n"
                     "void* = " << something << "\n"
                     "ptrConstCComPortInfo_t = " << c << "\n";
    }

private:
    std::string instance_name;
};

// and a free function to call
void free_func(void* something, ptrConstCComPortInfo_t c) {
    std::cout << "free_func_called\n"
                 "void* = " << something << "\n"
                 "ptrConstCComPortInfo_t = " << c << "\n";
}

int main() {
    // some instances of the class
    foo via_bind("called_via_bind");
    foo via_lambda("called_via_lambda");

    ptrConstCComPortInfo_t bork = nullptr; // dummy value

    // a vector of callback subscribers
    std::vector<function_t> subscribers{
        &free_func,
        std::bind(&foo::bar, &via_bind, std::placeholders::_1, std::placeholders::_2),
        [&via_lambda](void* p, ptrConstCComPortInfo_t c) { via_lambda.bar(p, c); }
    };

    // perform callbacks
    for(auto& cb : subscribers) {
        cb(nullptr, bork);
    }
}

Выход:

free_func_called
void* = 0
ptrConstCComPortInfo_t = 0
foo::bar(called_via_bind) called
void* = 0
ptrConstCComPortInfo_t = 0
foo::bar(called_via_lambda) called
void* = 0
ptrConstCComPortInfo_t = 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...