首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在没有C++11的情况下在C++中进行回调的最干净的方法?

在没有C++11的情况下在C++中进行回调的最干净的方法?
EN

Stack Overflow用户
提问于 2016-09-17 02:09:20
回答 4查看 563关注 0票数 3

在C++中回调类的最干净的方法是什么?

我通常创建如下函数:

代码语言:javascript
运行
复制
void registerCallback(void(*callback)(void* param), void* param);

然后这样叫它:

代码语言:javascript
运行
复制
foo->registerCallback(callbackStatic, this);

然后,我在类中添加一个静态函数,如下所示:

代码语言:javascript
运行
复制
static void callbackStatic(void* param)
{
    ((Type*)(param))->callback();
}

它是有效的,但它很痛苦。我必须为每个回调函数创建两个函数。如果我可以使用C++11,我会使用lambda。Qt有一个非常好的信号和槽机制,但需要一个特殊的预编译器。

我正在编写一个库,所以我想尽可能地降低要求。没有C++11,没有boost等等。有没有一种方法可以只使用C++03来构建一个lambda或signal/slot 'like‘回调系统?

EN

回答 4

Stack Overflow用户

发布于 2016-09-17 02:22:35

如果您能够从头开始,我建议不要在C++中使用函数作为回调函数。取而代之,使用对象。

代码语言:javascript
运行
复制
struct CallbackHandler { virtual void doit() = 0; };

void registerCallback(Callbackhandler* handler);

然后

代码语言:javascript
运行
复制
struct MyCallbackHandler : public CallbackHandler { ... };

registerCallback(new MyCallbackHandler());
票数 4
EN

Stack Overflow用户

发布于 2016-09-17 02:39:45

这可能有点复杂,但对我来说很有效:

代码语言:javascript
运行
复制
#include <functional>
#include <iostream>
#include <vector>

class C {
public:
    void foo() {
        std::cout << "foo" << std::endl;
    }
};

class D {
public:
    void bar() {
        std::cout << "bar" << std::endl;
    }
};

class abstract_bind {
public:
    virtual void operator()() = 0;
    virtual ~abstract_bind() {}
};

template <typename F, typename T>
class bind : public abstract_bind {
public:
    bind(F f_, T *t_) : f(f_), t(t_) {}

    virtual void operator()() {
        f(t);
    }

private:
    F f;
    T *t;
};


int main() {
    C c1, c2;
    D d;

    std::vector<abstract_bind*> v;

    v.push_back(new bind<std::mem_fun_t<void, C>, C>(std::mem_fun(&C::foo), &c1));
    v.push_back(new bind<std::mem_fun_t<void, C>, C>(std::mem_fun(&C::foo), &c2));
    v.push_back(new bind<std::mem_fun_t<void, D>, D>(std::mem_fun(&D::bar), &d));

    for (size_t i=0; i<v.size(); ++i)
        (*v[i])();

    for (size_t i=0; i<v.size(); ++i)
        delete v[i];

    return 0;
}

其基本思想是使用std::mem_fun获取对象的成员函数,并将相应的this指针绑定到该成员函数以获得“普通”函数。

票数 1
EN

Stack Overflow用户

发布于 2016-09-17 04:30:41

您可以保留C风格的回调,并使用一个结构来调用成员函数:

代码语言:javascript
运行
复制
// C-style callback
// ================

void(*registered_callback)(void* param) = 0;
void* registered_param = 0;
void registerCallback(void(*callback)(void* param), void* param) {
    registered_callback = callback;
    registered_param = param;
}
void unregisterCallback(void(*callback)(void* param), void* param) {
    registered_callback = 0;
    registered_param = 0;
}

// Invoker
// =======

struct InvokerBase {
    static void callInvoker(void* invoker) {
        reinterpret_cast<InvokerBase*>(invoker)->apply();
    }

    virtual void apply() const = 0;
};

template <typename T>
class Invoker : public InvokerBase
{
    public:
    Invoker(T& object, void(T::*function)())
    : object(&object), function(function)
    {
        registerCallback(callInvoker, this);
    }
    ~Invoker() {
        unregisterCallback(callInvoker, this);
    }

    void apply() const {
        (object->*function)();
    }

    private:
    Invoker(const Invoker&); // no copy
    Invoker& operator = (const Invoker&); // no copy

    T* object;
    void (T::*function)();
};


// Test
// ====

#include<cassert>
#include<iostream>

struct Type {
    void print() { std::cout << "Hello\n"; }
};

int main()
{
    Type x;
    {
        Invoker<Type> print_invoker(x, &Type::print);
        registered_callback(registered_param);
    }
    assert(registered_callback == 0);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39537686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档