5,699,997 members and growing! (14,166 online)
Email Password   helpLost your password?
Languages » C / C++ Language » Delegates     Intermediate

Yet Another C#-style Delegate Class in Standard C++

By Yingle Jia

This article describes a C#-style delegate class completely written in standard C++.
VC7.1, C++, WindowsVS.NET2003, Visual Studio, Dev

Posted: 27 Aug 2005
Updated: 6 Jan 2006
Views: 44,241
Bookmarked: 40 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
43 votes for this Article.
Popularity: 7.66 Rating: 4.69 out of 5
2 votes, 4.7%
1
1 vote, 2.3%
2
2 votes, 4.7%
3
4 votes, 9.3%
4
34 votes, 79.1%
5

Introduction

Delegates and events are definitely cool features of .NET/C# and there are already many attempts to simulate them in standard C++. The Delegate class described in this article tries to provide a complete and easy to use solution for using delegates in standard C++. Your feedback is welcome.

Design Goals

There are already several good delegate implementations on CodeProject. However, there is still no solution good enough for broad developers. For example, some implementations do not support multicast delegates (which is a must for events), some implementations do not support function objects (functors), some implementations are hard to use (syntax). So the design goals of my Deletgate class are:

  • Support all C++ callable entities, including static functions, member functions and functors.
  • Support single-cast and multicast in one Delegate class, so users don't have to implement multicast functionalities themselves.
  • Easy to understand and use.

Examples

1. Using delegates

#include "AcfDelegate.h"

using namespace Acf;

static void H() { ... }

class Foo {
public:
    void G() { ... }
};

class Foo2 {
public:
    void operator()(int n) { ... }
};

// Create delegate a which attaches to a static function

Delegate<void ()> a(&H);
assert(a == &H);

// Create delegate b which attaches

// to an instance and a member function

Foo foo;
Delegate<void ()> b(&foo, &Foo::G);
assert(b == std::make_pair(&foo, &Foo::G);

// Create delegate c from a

Delegate<void ()> c = a;
assert(c == &H);

// Create delegate d which attaches to a function object

Delegate<void (int)> d(Foo2());

// Call delegates

a();
d(100);

// Combine/remove delegates

d += &H;
d += std::make_pair(&foo, &Foo::G);
d -= std::make_pair(&foo, &Foo::G);
d -= &H;

2. Using events

class Button {
public:
    Delegate<void ()> Click;
};

Button btn;
btn.Click += &F;
btn.Click += std::make_pair(&o, &MyObj::G);
btn.Click();
btn.Click -= std::make_pair(&o, &MyObj::G);

3. Using events (advanced)

You may want more control on how event handlers are managed and fired, for example, you care about thread safety.

class Button {
private:
    Delegate<void ()> click;
    Mutex mutex;

public:
    template <class T>
    void add_Click(const T& h) {
        ScopedLock lock(this->mutex);
        this->click += h;
    }
    template <class T>
    void remove_Click(const T& h) {
        ScopedLock lock(this->mutex);
        this->click -= h;
    }

protected:
    void OnClick() { if (this->click) this->click(); }
};

btn.add_Click(&F);
btn.add_Click(std::make_pair(&o, &MyObj::G));

Delegate Class

namespace Acf {

template <class TSignature>
class Delegate; // no body


template <class R, class T1, class T2, ..., class TN>
class Delegate<R (T1, T2, ..., TN)> {
// Constructor/Destructor

public:
    Delegate();
    template <class TFunctor>
    Delegate(const TFunctor& f);
    template <class TPtr, class TFunctionPtr>
    Delegate(const TPtr& obj, const TFunctionPtr& mfp);
    Delegate(const Delegate& d);
    ~Delegate();

// Properties

public:
    bool IsEmpty() const;
    bool IsMulticast() const;

// Methods

public:
    template <class TFunctor>
    void Add(const TFunctor& f);
    template <class TPtr, class TFunctionPtr>
    void Add(const TPtr& obj, const TFunctionPtr& mfp);

    template <class TFunctor>
    bool Remove(const TFunctor& f);
    template <class TPtr, class TFunctionPtr>
    bool Remove(const TPtr& obj, const TFunctionPtr& mfp);

    void Clear();

// Operators

public:
    operator bool() const;
    bool operator!() const;

    template <class TFunctor>
    Delegate& operator=(const TFunctor& f);
    Delegate& operator=(const Delegate& d);

    template <class TFunctor>
    Delegate& operator+=(const TFunctor& f);

    template <class TFunctor>
    friend Delegate operator+(const Delegate& d, const TFunctor& f);
    template <class TFunctor>
    friend Delegate operator+(const TFunctor& f, const Delegate& d);

    template <class TFunctor>
    Delegate& operator-=(const TFunctor& f);

    template <class TFunctor>
    Delegate operator-(const TFunctor& f) const;

    template <class TFunctor>
    friend bool operator==(const Delegate& d, const TFunctor& f);
    template <class TFunctor>
    friend bool operator==(const TFunctor& f, const Delegate& d);

    template <class TFunctor>
    friend bool operator!=(const Delegate& d, const TFunctor& f);
    template <class TFunctor>
    friend bool operator!=(const TFunctor& f, const Delegate& d);

    R operator()(T1, T2, ..., TN) const;
};

} // namespace Acf

The TFunctor template parameter in the Delegate class supports static functions, member functions (via std::pair class that wraps an object pointer and a member function pointer) and functors. The TPtr template parameter for member functions support plain pointers (e.g. Foo*) and smart pointers (e.g. boost::shared_ptr<Foo>).

Notes

  • You must enable runtime type information (RTTI) in your project in order to use the Delegate class.
  • The current implementation supports up to six function parameters, which should be enough for most applications (and in general it's a bad practice to have more than six parameters).
  • There are no operators == and != for comparing delegates, because they are impossible to implement correctly for functors (see boost.function).
  • The current implementation is not optimized for performance. However, it should be OK for most applications.

History

  • 12/24/2005: changed the exception behavior when an empty delegate is called - if the delegate return type is void, then no exception will be thrown, otherwise an InvalidCallException will be thrown.
  • 8/28/2005: initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Yingle Jia


Yingle Jia is a software engineer located in Beijing, China. He currently works at IBM CSDL (China Software Development Lab). His interests include C++/COM/C#/.NET/XML, etc. He likes coding and writing.

He is the creator of ACF (Another C++ Framework) project. See http://acfproj.sourceforge.net/.

He also has a blog at http://blogs.wwwcoder.com/yljia/

Occupation: Web Developer
Location: China China

Other popular C / C++ Language articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 23 of 23 (Total in Forum: 23) (Refresh)FirstPrevNext
Generalbrilliantmemberf28:38 2 Aug '08  
Generalstatuc member function [modified]memberdelaneyj22:21 26 Feb '07  
Generalcompile error with gccmemberzhangzq7122:34 28 Jun '06  
GeneralEmpty delegatesmemberflapflap2:36 14 Oct '05  
GeneralRe: Empty delegatesmemberYingle Jia17:26 15 Jan '06  
GeneralSome RemarksmemberRoland Pibinger11:50 5 Sep '05  
GeneralRe: Some RemarkssussYingle Jia16:46 5 Sep '05  
GeneralRe: Some RemarksmemberRoland Pibinger8:41 6 Sep '05  
GeneralRe: Some RemarksmemberZac Howland21:51 11 Jan '06  
GeneralRe: Some RemarksmemberYingle Jia15:50 12 Jan '06  
GeneralRe: Some RemarksmemberZac Howland20:26 12 Jan '06  
GeneralRe: Some RemarksmemberYingle Jia17:15 15 Jan '06  
GeneralVariable Template Parametersmemberarmentage7:46 1 Sep '05  
GeneralRe: Variable Template ParameterssussYingle Jia16:19 1 Sep '05  
GeneralRe: Variable Template Parametersmemberarmentage4:29 6 Sep '05  
GeneralRe: Variable Template ParametersmemberZac Howland21:59 11 Jan '06  
Generalcool!sussPeifeng, Gu0:23 29 Aug '05  
GeneralRe: cool!memberhashimsaleem3:42 6 Jul '07  
GeneralBoost.SignalssitebuilderUwe Keim4:03 28 Aug '05  
GeneralRe: Boost.SignalssussYingle Jia4:50 28 Aug '05  
GeneralRe: Boost.Signalsmemberlxwde16:35 28 Aug '05  
GeneralRe: Boost.SignalssussAnonymous17:20 29 Aug '05  
GeneralRe: Boost.SignalsmemberJohn M. Drescher3:14 30 Aug '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 6 Jan 2006
Editor: Smitha Vijayan
Copyright 2005 by Yingle Jia
Everything else Copyright © CodeProject, 1999-2008
Web18 | Advertise on the Code Project