Click here to Skip to main content
Licence CPOL
First Posted 29 Mar 2007
Views 13,949
Downloads 101
Bookmarked 11 times

An event mechanism for C++ using an interface based delegate

By | 29 Mar 2007 | Article
Introducing a simple event mechanism for C++ using a C# style delegate.

Introduction

This article introduces a very simple and comfortable event mechanism in C++. In many cases, a delegate in C++ is hard to understand because of its complexity. The attached code is a sample that uses the combination of the C# delegation style and Java's inner class callback style. It can show you an example of an easy event mechanism.

Event Processing

// delegate
struct ISampleEventHandler : public IEventHandler
{
    virtual void callback( IUnknown* object, const SampleEventArgs& e ) = 0;
    typedef SampleEventArgs _EventArgs; // passive polymorphism using typedef
};

// event
template<typename T>
class Event
{
public:
    void invoke(IUnknown* object, const EventArgs& e = EventArgs::Empty)
    {
        std::set<T*>::iterator iter;
        for (iter = m_EventHandler.begin();
            iter != m_EventHandler.end();
            ++iter)
        {
            // this code can promise the type-safe callback because
            // of the polymorphism using typedef in delegate
            (*iter)->callback(object, static_cast<const T::_EventArgs&>(e));
        }
    }
    void operator+=(T* eventHandler)
    {
        m_EventHandler.insert(eventHandler);
    }

    void operator-=(T* eventHandler)
    {
        m_EventHandler.erase(eventHandler);
    }

protected:
    std::set<T*> m_EventHandler;
};

Using the Code

We need an abstract parent class to identify the event sender.

class IUnknown
{
public:
 virtual ~IUnknown() {}
 virtual std::string name() = 0;
};

Here is the event sending class:

class Callee : public IUnknown
{
public:
// declare the event.
 Event<ISampleEventHandler> SampleEvent;
public:
 void test()
 {
  SampleEventArgs e;
  e.sampleData = 10;
  e.sampleData2 = 20;

// event occur.
  SampleEvent.invoke(this, e);
 }
 std::string name() { return "callee"; }
};

Here is the event receiving class:

class Caller : public IUnknown
{
public:
 Caller()
 {
// register Caller's inner class object to Callee.
  m_Callee.SampleEvent += &sampleEventHandler;
 }
 ~Caller()
 {
// unregister Caller's inner class object from Callee.
  m_Callee.SampleEvent -= &sampleEventHandler;
 }
 void test()
 {
  m_Callee.test();
 }
private:
 void print(IUnknown* object, const SampleEventArgs& e)
 {
  std::cout << object->name().c_str() << std::endl;
  std::cout << e.sampleData << std::endl;
  std::cout << e.sampleData2 << std::endl;
 }
 std::string name() { return "caller"; }
private:
 class SampleEventHandler : public ISampleEventHandler
 {
  void callback( IUnknown* object, const SampleEventArgs& e )
  {
    // to access outer class's member function.
    Caller* outer = reinterpret_cast<Caller*>((char*)this - 
                       offsetof(Caller, sampleEventHandler));

    outer->print(object, e);
  }
 } sampleEventHandler;
private:
 Callee m_Callee;
};

Points of Interest

You can easily find the reason why using the delegate is nice. It can break the cyclic dependency of each class - the 'Caller' depends on the 'Callee' but the 'Callee' does not have dependency with any classes.

History

  • 2007. 03. 29 - Initially released.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

choiday



Korea (Republic Of) Korea (Republic Of)

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Questionstd::set ?!? Pinmemberemilio_grv3:28 31 Mar '07  
AnswerRe: std::set ?!? Pinmemberchoiday5:25 31 Mar '07  
GeneralSome Suggestions PinmemberStuart Dootson23:13 29 Mar '07  
GeneralRe: Some Suggestions Pinmemberchoiday14:57 30 Mar '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 29 Mar 2007
Article Copyright 2007 by choiday
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid