2013-08-06 3 views
0

Я хочу определить контейнер в базовом классе, который содержит функцию obj или что-нибудь, что может привести к моей цели. Эти функции obj могут вызывать функции производных классов. все они принимают одинаковые параметры.в базовом классе, как определить контейнер, содержащий функцию obj, которая может быть любой func производного класса?

#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); 
} 
+0

Это не будет правильно работать в любом случае, так как вы делаете 'UB', когда вы передаете' fobj' типа '' Foo' к print_ttt', и, таким образом, используя '' vtable' из Foo' в вызовите функцию, которая находится только в 'Foo2'. –

+0

Есть ли какая-то особая причина, по которой вы не можете просто сохранить кучу ссылок Foo (и производных) и вызвать одну и ту же виртуальную функцию для каждого объекта? Возможно, ваш пример слишком прост для того, что вы действительно хотите сделать, но похоже, что вы должны это сделать. –

+0

Вы правы. Но как я могу заставить его работать? Я хочу, чтобы базовый класс запускал набор функций зарегистрированного производного класса, которые принимают одинаковые параметры. – doufunao

ответ

1

Вот способ добиться того, что ваш код выглядит как он пытается сделать, без использования указателей на функции:

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(); 
} 

Теперь, вполне могут быть причины, чтобы сделать это совершенно по-другому, но я не почему бы вам не нужны как виртуальные функции, так и наследование, а также объекты/указатели функций. Это, кажется, совершенно неправильно для меня («плохо пахнет»)

Edit:

Вот то, что я придумал, что решает тип проблемы, вы можете описать после редактирования исходного вопроса.

#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); 
    } 
} 
+0

благодарит за код. но можете ли вы сделать это с помощью функционального объекта или ptr? из-за некоторых деталей, я не могу сделать это на вашем пути, потому что мне нужно использовать func ptr. причина 1: моя настоящая проблема не работает ** все ** обратные вызовы. базовому/вызывающему нужно выбрать правильный, основанный на вводе. (я снова рассмотрел пример. извините :)) Причина 2: я хочу знать, может ли объект функции или ptr решить мою проблему. Я считаю, что это возможно, но я просто не понимаю этого. – doufunao

+0

Я вернусь к вам утром, здесь будет 1,30 ночи, и я недостаточно проснулся, чтобы продумать все различные последствия, но я думаю, что вам нужен класс интерфейса, который затем вы получите объект из и выполнять эту реализацию таким образом - по-прежнему не так (на мой взгляд) построить систему, основанную на указателях функций на C++ (как правило, исключения существуют, но я не думаю, что это один из тех). –

+0

@ doufunao: редактирование сделано. –