Click here to Skip to main content
15,889,362 members
Articles / Programming Languages / C++

MFC Delagates

Rate me:
Please Sign up or sign in to vote.
2.11/5 (7 votes)
13 May 2007CPOL2 min read 19.9K   154   12  
A template class that can simulate C# delegates in MFC.

Introduction

The arrival of .NET brought some very nice approaches and techniques. Of course, one main reason of .NET code efficiency (I mean from a developer's scope) is that .NET languages are fully and exclusively object oriented.

One very nice attribute of .NET (and especially of C#) is delegates. Delegates are defined as member variables, and can hold references to functions.

Can C++ (and I meal real (native) C++) simulate this approach? While I am developing a very nice project in MFC, I realized that I can do (or even simulate) everything (with C++) that all other languages do. The only thing that I have noticed C++ does not have are function definitions in functions, as Delphi and Pascal have.

Anyway, because I wanted to get rid of non object oriented event handlings that MFC have (DECLARE MAPS... etc.), I tried to develop a template class that simulates C# delegates. And it wasn't so difficult.

The Class

The class is as follows:

C++
//
// 
template <class FP, class SENDER,
class ARG1=int, class ARG2=int, class ARG3=int, class ARG4=int,
class ARG5=int, class ARG6=int, class ARG7=int, class ARG8=int>
class GDDelegateS
{
public:
    struct FPDATA
    {
        FP fp; //function pointer
        void *data;
    };
public:
    GDDelegateS()
    {
        m_List = NULL;
        m_ListCount = 0; 
    }
    virtual ~GDDelegateS()
    {
        Clear();
    }
protected:

    FPDATA *m_List;
    int m_ListCount;
public:
    void Add(FP funct, void *data)
    {
        FPDATA *nList = new FPDATA[m_ListCount+1];
        FPDATA *f=NULL;
        for(int i=0;i<m_ListCount;i++)
        {
            if(funct==m_List[i].fp && data == m_List[i].data)
            {
                delete []nList;
                return;
            }
            nList[i].data = m_List[i].data;
            nList[i].fp = m_List[i].fp;
        }
        nList[i].data = data;
        nList[i].fp = funct;
        if(m_List)
        delete m_List;
        m_List = nList;
        m_ListCount++;
    }

    //no arguments
    void Send(SENDER sender)
    {
        for(int i=0;i<m_ListCount;i++)
            (*m_List[i].fp)(sender, m_List[i].data);
    }

    //one argument 
    void Send(SENDER sender, ARG1 arg1)
    {
        for(int i=0;i<m_ListCount;i++)
            (*m_List[i].fp)(sender, m_List[i].data, arg1);
    }

    //two arguments
    void Send(SENDER sender, ARG1 arg1, ARG2 arg2)
    {
        for(int i=0;i<m_ListCount;i++)
            (*m_List[i].fp)(sender, m_List[i]data, arg1, arg2);
    }

    //three arguments
    void Send(SENDER sender, ARG1 arg1, ARG2 arg2, ARG3 arg3)
    {
        for(int i=0;i<m_ListCount;i++)
            (*m_List[i].fp)(sender, m_List[i]data, arg1, arg2, arg3);
    }

    //four arguments
    void Send(SENDER sender, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4)
    {
        for(int i=0;i<m_ListCount;i++)
            (*m_List[i].fp)(sender, m_List[i].data, arg1, arg2, arg3, arg4);
    }

    //five arguments
    void Send(SENDER sender, ARG1 arg1, ARG1 arg2, 
              ARG3 arg3, ARG4 arg4, ARG5 arg5)
    {
        for(int i=0;i<m_ListCount;i++)
            (*m_List[i].fp)(sender, m_List[i].data, arg1, arg2, arg3, arg4, arg5);
    }

    void Clear()
    {
        if(m_List)
        {
            delete []m_List;
            m_ListCount = 0;
            m_List = NULL;
        }
    }
};

//

Using the Code

As you can see, this class has 10 template arguments. The first two are required, and are:

  1. the desired function type to handle the event.
  2. The type of the sender object (void * if it is not required).

The function prototype must have also at least two arguments:

  1. The type of the sender object (of course, must be identical to the second template argument).
  2. A void pointer. This pointer points to (extra) data that is being passed to the GDDelegiateS variable when the event handling function is defined as an event handler.

The function prototype can have up to 10 arguments. The third argument of the function prototype must be identical to the template third argument, and the fourth and the fifth and so on.

The function prototype can not be a member of a class. That's why I call this class GDDelegateS.

Let's see an example to understand better:

C++
//
// Any source code blocks look like this
// define a function prototype
typedef void (*_fpSimpleFunct)(void* /*sender*/, void* /*extra_data*/);
// then declare the function:
void DoSomething(void *sender, void *extra_data);
// then define a delegate (as variable):
GDDelegateS<_fpSimpleFunct, void *> m_ASimpleDelegate;
//

Suppose we have the main function:

C++
//
void main()
{
    m_ASimpleDelegate.Add((_fpSimpleFunct)DoSomething, 
              NULL/*do you want to send initialization data?*/);
    //now send the delegate...
    m_ASimpleDelegate.Send(NULL/*who is the sender?*/);
}

void DoSomething(void *sender, void *extra_data)
{
    cout<<"Here is the delegate!";
}
//

As you can see:

  1. This class keeps more than one function pointer.
  2. If you try to pass the same function with the same data twice, Add won't do it.
  3. The Send function you invoke must have one argument less than the function's prototype.
  4. Use the Clear function to reset the prototype.
  5. I did not implement Send for 6, 7, and 8 arguments. It is not difficult for you to do it.

I am sure you know that delegates can be used in several different ways. Thank you a lot for your time.

License

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


Written By
Web Developer
Greece Greece
My name is George Drivas.
The programming was for me the main job. Now I am coding mostly for fun. My main language is C\C++ and I am using the most common developments tools. I am interesting mostly for the MFC development. This site is (in my opinion) the best for MFC development. I hope that I will be able to contribute in this community.

Comments and Discussions

 
-- There are no messages in this forum --