C ++函数指针和成员函数指针

时间:2018-04-03 14:11:31

标签: c++ function pointers

有没有办法为函数和成员函数使用函数指针?

我想创建一种事件句柄,它可以保存类的成员函数,同时它应该能够拥有“普通”函数指针。

编辑:我找到了解决方案。可能不是最好的一个而是一个;

Event.h

#include <map>

class BasicEvent {

public:

    BasicEvent(int id) : eventId(id)
    {}

    int GetId() const
    { 
        return eventId;
    }

    virtual void ObjectMethode() {}

protected:

    const int eventId;

};

class BasicEventHandler {

public:

    void Trigger(BasicEvent* event)
    {
        if (this->eventMap.find(event->GetId()) != this->eventMap.end()) {
            eventMap[event->GetId()](event);
        }
    }

    void AddEvent(int id, std::function<int(BasicEvent*)> eventFunction)
    {
        eventMap[id] = eventFunction;
    }

    void RemoveEvent(int id)
    {
        this->eventMap.erase(id);
    }

private:

    std::map<int, std::function<int(BasicEvent*)>> eventMap;

};

的main.cpp

class CustomEvent : public BasicEvent {

public:

    CustomEvent(int id) : tq::BasicEvent(id)
    {
    x = 9;
    y = 8;
    }

    struct {
    int x;
    int y;
};

    void ObjectMethode()
    {
    std::cout << this->eventId << " Custom Event: X: " << x << " Y: " << y << '\n';
    }

};


int main() {
    BasicEventHandler myHandler;

    myHandler.AddEvent(0, [&](BasicEvent* event) {
        std::cout << " EVENT <" << event->GetId() << "> Triggered!\n";
    return 0;
    });

    myHandler.AddEvent(1, [&](tq::BasicEvent* event) {
    event->ObjectMethode();
    return 0;
    });

    myHandler.Trigger(&BasicEvent(0));
    myHandler.Trigger(&CustomEvent(1));

    return 0;
}

3 个答案:

答案 0 :(得分:2)

C ++ 11和Lambdas .. yay !!

所以我们走了......

让我们有一个函数,你的事件处理程序将采用谓词(一个返回true或false的函数)和两个函数,即on_sucesson_error

如果test_predicate返回true,则应调用on_success,否则将调用on_error

template<typename Predicate, typename OnSucess, typename OnError>
void single_event_handler (Predicate && test_predicate,
                           OnSucess  && on_success,
                           OnError   && on_error)
{
    if( test_predicate() )
        on_success();
    else
        on_error();
}

现在是我们的来电方。 在这里,我们有3个函数可以放入这个模式中。

bool is_even(int num) { return !(num % 2); }
void on_even_found() { std::cout << "Number passed is even\n"; }
void on_odd_found() { std::cout << "Number passed is odd\n"; };

但正如您所看到的,is_even函数不适合test_predicate的签名。 is_even(int)只接受一个参数,而test_predicate()则不接受任何参数。

那我们该如何解决这个问题?

我们将它包装成另外一个函数和/或lambda,然后传递它。

指导原则:可以通过再添加一层来解决每个问题。

// wrap it in another function or lambda
auto is_5_even = []() { return is_even(5); };
auto is_4_even = []() { return is_even(4); };

现在,一旦我们的所有拼图准备就绪,我们就会创建自己的事件处理程序。

// caller side - pair the final structure
single_event_handler(is_5_even, on_even_found, on_odd_found);
single_event_handler(is_4_even, on_even_found, on_odd_found);

现在,通过使用绑定和函数指针,可以在预C ++ 11中实现此代码。 遗憾的是,std::bindstd::function是在C ++ 11中引入的,您必须使用其他替代方案,例如boost库。

此外,另一个包装器可以写在single_event_handler之上,它可以同时管理多个事件,但我认为我们必须创建另一个函数register_event,以便它可以有效地使用。 / p>

以下是完整的工作代码,供您参考(使用g++ -std=c++11编译)

#include <iostream>

template<typename Predicate, typename OnSucess, typename OnError>
void single_event_handler (Predicate && test_predicate,
                           OnSucess  && on_success,
                           OnError   && on_error)
{
    if( test_predicate() )
        on_success();
    else
        on_error();
}

bool is_even(int num) { return !(num % 2); }
void on_even_found() { std::cout << "Number passed is even\n"; }
void on_odd_found() { std::cout << "Number passed is odd\n"; };

int main()
{
    // caller side
    auto is_5_even = []() { return is_even(5); };
    auto is_4_even = []() { return is_even(4); };

    single_event_handler(is_5_even, on_even_found, on_odd_found);
    single_event_handler(is_4_even, on_even_found, on_odd_found);

    return 0;
}

答案 1 :(得分:1)

接受您的处理程序作为std::function,然后客户端可以传入他们想要的任何内容。无论是功能,lambdas,其他仿函数,你都可以命名。

模板将为您处理细节,客户可以选择他们希望如何调用。

答案 2 :(得分:1)

成员函数在哪里获得“this”指针? 这两个函数不能具有相同的签名。 也许,你最好的选择是创建一个lambda,它将捕获“this”,并将其发送给你的事件处理程序。

std::function将能够为您保留。