2011-03-03 19 views
5

Projemde, olayların bir işlev tarafından çağrılabileceği basit bir ileti sistemi eklemeye çalışıyorum; bu, çağrılan o olaya kayıtlı tüm geri aramalara neden olacaktır.C++: Sınıf üyesi işlev geri aramaları olarak işlevler

Şimdi, bunu yapmanın mantıksal yolu işlev göstergelerini kullanmaktır. Kaydetmek için işaretçiyi istenen geriçağırım işlevine olay yöneticisine iletmek mümkün olacaktır. Bir olay geri arama işlevi her zaman bir int döndürür ve bağımsız değişken olarak bir void* alır.

Ancak, statik genel işlevlerimi olay geri aramalarım olarak kaydetmek istemiyorum - sınıf üyesi işlevleri ile yapmak istiyorum.

  • Bunu, C++ ile gerçekleştirmek mümkün mü? farklı sınıfların üye işlevlerine işaretçiler çağırma ve çağırma, ancak aynı işlev üstbilgisiyle.

  • Bu mümkün değilse, bu konuda nasıl çalışabileceğime dair herhangi bir öneriniz var mı? Etkinlik dinleyicilerini doğrudan sınıflarıma eklemek istiyorum.

+0

Geçersiz olmamaya özen gösterin *. Genellikle C++ 'da gerekli değildir ve daha karmaşık sistemlerde garip hatalar için olasılıklar açar: derleyici yardımı olmadan gönderici ve alıcı arasındaki tutarlılığı zorlar. – stefaanv

cevap

0

Hayır, bu mümkün değildir (.net ile C++/cli yapmıyorsanız).

Şimdi, yine de statik işlevler oluşturabilir, bir nesneyi parametre olarak iletebilirsiniz ve yapacakları tek şey, bu işleve üye işlevinizi çağırmaktır. (Aslında ilk olarak bir döküm gerekecek).

3

Elbette mümkün! Boost.Signal2 ve Boost.Bind'a bir göz atın.

Boost.Signal2, tam olarak ihtiyacınız olan bir sinyal ve yuva sistemini temel olarak uygulamaktadır. Daha sonra, std::bind1st ve std::bind2nd ve std::bind2nd genelleştirmesi olan boost::bind öğelerini, temelde düşünebileceğiniz her şeyi (sizin durumunuzda, üye yöntemleri) almak için kullanabilirsiniz. Bu gerçekten güçlü. Bu resmi gör boost tutorial.

0

En yakınım, yönetilen statik bir üye işlevini geri arama olarak kaydetmektir. Statik üye, nesne (bu) işaretçisini olay işleyicisi tarafından gönderilen argümanlara ek olarak bir argüman olarak alır ve bunu üye işlevini çağırmak için kullanır.

class myClass{ 
public: 
    static void callback(void *arg, void *obj) 
    { 
    if (obj) 
     reinterpret_cast<myClass*>(obj)->cb(arg); 
    } 

private: 
    void cb(void *arg); 
}; 

Kayıt myClass::callback ve işleyicisi ile this. Geri döndürülebilecekler konusunda kısıtlanmış iseniz arg argümanlarının yapısına sarmanız gerekebilir.

1

Ben arşivlemek istediğiniz ama belki sen Sinyal/Slot mekanizması çeşit oluşturmak istiyorsanız Oldukça yararlı Boost Signals2

bakmak gerektiğini tam olarak emin değilim.

6

Evet, mümkün. C++0x has the function class that handles this, ve diğerleri gibi Boost benzer özelliklere sahip olduğunu işaret etti.

Ayrıca kendi rulo, ancak sözdizimi kalbin zayıf değildir:

#include <iostream> 

class Callable 
{ 
    public: 

     virtual ~Callable() {} 
     virtual int operator() (void* args) = 0; 
}; 

class CallableFreeFunction : public Callable 
{ 
    public: 

     CallableFreeFunction(int (*func)(void*)) : func_(func) {} 

     virtual int operator() (void* args) { return (*func_)(args); } 

    private: 

     int (*func_)(void*); 
}; 

template <typename tClass> 
class ClassMemberCallable : public Callable 
{ 
    public: 

     ClassMemberCallable(tClass* instance, int (tClass::*memberfunction)(void*)) : instance_(instance), memberfunc_(memberfunction) {} 

     virtual int operator() (void* args) { return (instance_->*memberfunc_)(args); } 

    private: 

     tClass* instance_; 
     int (tClass::*memberfunc_)(void*); 
}; 

class Foo 
{ 
    public: 

     int derp(void* args) 
     { 
      std::cout << args << '\n'; 
      return 2; 
     } 
}; 

int freefunctionfoo(void* args) 
{ 
    std::cout << "free" << args << '\n'; 
    return 2; 
} 

int main(int argc, char* argv[]) 
{ 
    Foo myfoo; 

    Callable* callable = new ClassMemberCallable<Foo>(&myfoo, &Foo::derp); 

    (*callable)(0); 

    delete callable; 

    callable = new CallableFreeFunction(freefunctionfoo); 

    (*callable)(0); 

    delete callable; 

    std::cin.get(); 

    return 0; 
} 

Bu opak bir şekilde serbest fonksiyonları ve üye fonksiyonlarını hem taşıma yolu gösterir. Bu basit bir örnektir ve çeşitli şekillerde daha genel ve sağlam yapılabilir. Ben sözdizimi yardım için bu sayfalara bakınız ediyorum: Ben de daha fazla fikir için bu bakarak öneririm

http://www.newty.de/fpt/index.html

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

:

İşte

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

1

olduğunu benim Böyle bir iş yapmak için çok iyi bir girişimde bulunmayın: Her şeyden önce bir temel olay işleyici sınıfına ihtiyacınız var, hadi şu an için EvtHandler diyelim:(

class Event; //implement this yourself, it shall contain general but good info about event class EvtHandler { public: virtual void handleEvent (Event & evt); }; 
Sonra bir şekilde olayları ele gerekiyordu her sınıf, bu sınıftan türetme olmalı ve kadar onlar kadar istediğiniz kadar aynı veri türü dönmek gibi yeni işlevler uygulayabilir Bu durumda void) ve aynı paramterleri (bu durumda Olay) elde edin. Şunun gibi:

class ShutdownMessageCenter 
{ 
typedef std::map<EventHandler *, event_func> ListenerMap; 
public: 

    void register (EvtHandler * handler, void(EvtHandler::*memFunc)(Event &)) { 
     m_lmap[handler] = memFunc; 
    } 

    void callListeners() { 
     Event shutdown_event (EM_SHUTDOWN /*just imagine this can mean something, idk*/); 
     ListenerMap::iterator itr = m_lmap.begin(); 
     for (; itr != m_lmap.end(); ++itr) { 
      EvtHandler * handler = itr->first; 
      void (EvtHandler::*func)(Event &) = itr->second; 
      (handler->*func)(shutdown_event); 
      } 
     } 

private: 
    ListenerMap m_lmap; 
}; 

Sonra için bu özel mesaj merkezi için EvtHandlers kayıt olabilir:

class Foo : public EvtHandler 
{ 
public: 
    void handleFooEvent (Event & event); 
}; 

Sonra gerektiğinde dinleyicileri ve sevk olayları kaydetmek zorunda her özel etkinlik, mesaj merkezleri hayata örnek!

ShutdownMessageCenter message_center; 
EvtHandler * some_handler = new EvtHandler(); 
Foo * some_foo = new Foo(); 
message_center.register (some_handler, &EvtHandler::handleEvent); 
message_center.register (some_foo, static_cast<void (EvtHandler::*)(Event &)>(&Foo::handleFooEvent); 
message_center.callListeners(); 

Ama bir kez daha bu hiç de iyi değil, sadece paylaşacağımı düşündüm! Dağınıklık için üzgünüm, haha!

İlgili konular