in base class, how to define a container to contain function obj which can be any func of derived class?

StackOverflow https://stackoverflow.com/questions/18092108

Вопрос

I want to define a container in the base class, which contains function obj or anything that can make my purpose happen. These function obj can call derived classes' functions. they all take same parameters.

#include <vector>
#include <functional>
#include <iostream>


class Foo {
    Foo() {}
    virtual ~Foo(){}

    virtual void init()
    { registerCallback(0, &Foo::print_ori ); }
    void print_ori(int i) const { std::cout << i << '\n'; }

    void registerCallback(int key, ??? cb ) // NOT SURE HOW TO DEFINE THIS
    {
        callbacks[key] = cb;
    }

    void runCallbacks(int key, int n)
    {
        auto i = callbacks.find(key);
        if (i != callbacks.end()) {
            (*i)(*this, n);
        }
    }

    std::map<int, std::function<void(const Foo&, int) > > callbacks; // obviously, it's wrong. how to fix it?
};
struct Foo2 : public Foo {
    Foo2(int num) : Foo(num) {}
    virtual void init()
    {
        Foo::init();
        registerCallback(11, &Foo2::print1 );
        registerCallback(12, &Foo2::print2 );
    }
    void print1(int i) const { std::cout << " - Foo2.p1 - " << i << endl; }
    void print2(int i) const { std::cout << " - Foo2.p2 - " << i << endl; }
};



int main()
{
    Foo* obj = new Foo2();
    obj->init();
    obj->runCallbacks(12, 456);
}
Это было полезно?

Решение

Here's a way to achieve what your code looks like it's trying to do, without using function pointers:

class Foo {
    Foo() {}
    virtual ~Foo(){}

    void print_ori(int i) const { std::cout << i << '\n'; }

    virtual void do_runCallbacks(int v)
    {
    }

    void runCallbacks()
    {
        print_ori(3)
        do_runCallBacks(3);
    }

};
struct Foo2 : public Foo {
    Foo2(int num) : Foo(num) {}

    void do_runcallbacks(int v)
    {
       print1(v);
       print2(v);
    }
    void print1(int i) const { std::cout << " - Foo2.p1 - " << i << endl; }
    void print2(int i) const { std::cout << " - Foo2.p2 - " << i << endl; }
};



int main()
{
    Foo* obj = new Foo2();
    obj->runCallbacks();
}

Now, there may well be reasons to do this completely differently, but I don't see why you should need both virtual functions and inheritance, AND function objects/function pointers. That seems quite wrong to me ("smells bad")

Edit:

Here's something I came up with, that solves the type of problem you describe after edits of the original question.

#include <iostream>
#include <map>

using namespace std;

class event_interface
{
public:
    virtual void action(int n) = 0;
};

class event_manager
{
public:
    event_manager(int n) : num(n) {}
    void register_event(int key, event_interface *eh) 
    { 
        handlers[key] = eh; 
    }
    void callback(int key)
    {
        auto h = handlers.find(key);
        if (h != handlers.end())
        {
        h->second->action(num);
        }
    }
private:
    map<int, event_interface *> handlers;
    int num;
};


class handler1 : public event_interface
{
public:
    void action(int n) { cout << "in handler1::action. n=" << n << endl; }
};

class handler2 : public event_interface
{
public:
    handler2(int n) : data(n) {}
    void action(int n) 
    { 
        cout << "in handler2::action. n=" << n 
         << " data = " << data << endl; 
    }
private:
    int data;
};

class multihandler 
{
private:
    class handler3: public event_interface
    {
    public:
    void action(int n) { cout << "in handler3::action. n=" << n << endl; }
    };

    class handler4: public event_interface
    {
    public:
    handler4(multihandler *m) : mh(m) {}
    void action(int n) 
        { 
        cout << "in handler4::action. n=" << n 
             << " data = " << mh->data << endl; 
        }
    private:
    multihandler* mh;
    };

public:
    multihandler(event_manager& em) : h4(this)
    {
        em.register_event(62, &h3);
        em.register_event(63, &h4);
        data = 42;
    }

private:
    handler3 h3;
    handler4 h4;
    int data;
};


int main()
{
    event_manager mgr(3);
    handler1 h1;
    handler2 h2(77);

    multihandler mh(mgr);

    mgr.register_event(12, &h1);
    mgr.register_event(13, &h2);

    int evts[] = { 12, 63, 62, 13, 18 };

    for(auto i : evts)
    {
    cout << "Event: " << i << endl;
    mgr.callback(i);
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top