Click here to Skip to main content
15,867,488 members
Articles / Programming Languages / Objective C

C++0x Dynamic Message Passing

Rate me:
Please Sign up or sign in to vote.
4.53/5 (15 votes)
26 Nov 2010CPOL2 min read 38.1K   352   22   9
C++0x Dynamic Message Passing Ala Objective-C

Introduction

Sometimes it is useful to have dynamic message passing as in Objective-C. The small header presented below allows any class to contain a dynamic message map that can be used to add methods dynamically to an object.

Background

Objective-C is deemed more flexible than C++ because it allows a form of dynamic dispatch known as message passing.

Message passing is a form of dynamic dispatch that does not require implementation of a specific interface type. When sending a message to a target object, it is unknown to the compiler if the message can be handled by the object or not. It is only during the execution of the program that conformance to an interface is discovered.

Message passing is quite flexible because it does not require a lot of planning. Objective-C has been praised for this feature as more flexible than C++. This article demonstrates how easy it is to do the same in standard C++ (c++0x).

Using the Code

Using the code is very easy. The following steps have to be followed:

  • Include the header "mp_object.hpp" in your project.
  • Inherit from class mp_object.
  • Add dynamic methods to your object by using the method 'add_method'.

In order to add methods to an object, you need a prototype function. A prototype function can be any free-standing function. The following code is an example of how to declare prototypes and add dynamic methods to your code:

C++
#include <iostream>
#include "mp_object.hpp"
using namespace std;

//prototype method
void draw() {}

//prototype method
void setColor(int color) {}

//rectangle
class rect : public mp_object {
public:
    //constructor
    rect() {
        add_method(::draw, &rect::draw);
        add_method(::setColor, &rect::setColor);
    }

    //draw
    void draw() {
        cout << "rect\n";
    }

    //set color
    void setColor(int color) {
        cout << "rect color = " << color << "\n";
    }
};

//circle
class circle : public mp_object {
public:
    //constructor
    circle() {
        add_method(::draw, &circle::draw);
        add_method(::setColor, &circle::setColor);
    }

    //draw
    void draw() {
        cout << "circle\n";
    }

    //set color
    void setColor(int color) {
        cout << "circle color = " << color << "\n";
    }
};

You can invoke an object dynamically like this:

C++
int main() {
    rect r;
    circle c;

    r.invoke(draw);
    c.invoke(draw);

    r.invoke(setColor, 10);
    c.invoke(setColor, 20);

    return 0;
}

The output of the above is:

rect
circle
rect color = 10
circle color = 20

Implementation Details

The implementation is very simple, really. The class mp_object has a hash map of prototype function pointers to method pointers. When a method is invoked, the appropriate method pointer is retrieved from the prototype function and executed.

In order to minimize memory usage, the class mp_object uses copy on-write: a method map is shared between many instances, until it is modified. If modified, the method map is copied and the change is applied to the copy.

The mp_object code is 39 lines of code, thanks to C++0x. If a previous version of C++ was used, then a lot of boilerplate code would be needed for doing essentially the same thing.

The code can easily be expanded with new capabilities; for example, querying an object if it supports a specific method or a form of reflection (combined with macros). These are beyond the scope of this short article, though.

History

  • 26th November, 2010: Initial post

License

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


Written By
Software Developer (Senior)
Greece Greece
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 2 Pin
Wessam Fathi14-Dec-10 4:33
Wessam Fathi14-Dec-10 4:33 
GeneralGood idea, also I suggest putting the "message" functions in a separate namespace Pin
wtwhite9-Dec-10 1:49
wtwhite9-Dec-10 1:49 
GeneralRe: Good idea, also I suggest putting the "message" functions in a separate namespace Pin
Achilleas Margaritis9-Dec-10 2:10
Achilleas Margaritis9-Dec-10 2:10 
GeneralMy vote of 5 Pin
Jim Crafton2-Dec-10 9:22
Jim Crafton2-Dec-10 9:22 
GeneralReally good start Pin
Jim Crafton2-Dec-10 9:16
Jim Crafton2-Dec-10 9:16 
GeneralRe: Really good start Pin
Achilleas Margaritis3-Dec-10 2:28
Achilleas Margaritis3-Dec-10 2:28 
Thank you for your kind words.

I don't think that I can explain it further. It's extremely simple:

-the class mp_object has an std::map member.
-the map key is a pointer to a function.
-the map value is a pointer to a method.
-the type system makes certain that function signatures and method signatures match.
-when a method is invoked, the appropriate method ptr is pulled from the map by using the function ptr as a key.

I believe that this is faster than ObjC, because ObjC uses strings as keys to its maps.
GeneralMy vote of 2 Pin
xComaWhitex29-Nov-10 9:57
xComaWhitex29-Nov-10 9:57 
GeneralMy vote of 4 Pin
alex_dacosta29-Nov-10 2:20
alex_dacosta29-Nov-10 2:20 
GeneralMy vote of 1 Pin
gbb2127-Nov-10 10:36
gbb2127-Nov-10 10:36 

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

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