通过回调提供数据

通过回调提供数据

本文介绍了通过回调提供数据的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在用 C 编程一段时间后,我最近又回到了 Visual C++,因为回调更容易.

I have recently returned to Visual C++ after a while programming in C where callbacks are much easier.

我有一个控制 0..* 连接设备的单例类.我的想法是在这个类中创建一个函数,它将迭代一组连接的设备并通过回调将其发布到任何可能需要它的地方.

I have a singleton class which controls 0..* connected devices.My idea is to create a function in this class which will iterate over the set ofconnected devices and publish it via a callback to whatever might require it.

例如

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"传递给单例类并将其反射回来.

In the first instance the consumer is an MFC dialog class which works fine if it's callback is static. However in order to access member data/functions of the dialog class I would need to pass 'this' to the singleton class and have it reflected back.

例如

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 类应该不知道它的使用者.

My question - Is there a better way of doing this? Static functions feel like a kludge and I do not want the Singleton class to be constrained by how it might be used.If I remove the static on getPorts it will not compile. To repeat myself the Singleton class should have no knowledge of it's consumer.

推荐答案

在 WhozCraig 提供的出色提示的帮助下,我想到了:

With help from the excellent hints from WhozCraig, this is what I came up with:

#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

这篇关于通过回调提供数据的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 08:37