Nice C++ object oriented code basically means writing everything in objects/classes. However, not everything we need in programming is classes. This article concentrates on callback functions, and presents a C++ implementation of delegates which doesn’t use pointers to functions.
It’s not surprising that callback functions will usually look ugly in C++ code. Pointers to member functions are usually a mess. It is mainly because they need the “this” pointer as a parameter. Observe the following example:
class A { public: int func (); }; ... int (A::*pmf)(); pmf = &A::func; A a; A *pa = &a; (a.*pmf)();
C++ was meant to be nicer than this, wasn’t it?
Implementing Delegates in C++
If you’re familiar with C# programming, one of the new bright ideas in C# is “Delegates”. If you get to the bottom of it, delegates can actually be easily implemented in C++ using regular classes, as shown below.
As a rule of thumb, use the ideas of the following code whenever you want to implement a callback function in C++ and you won’t get disappointed.
Implementing a C++ delegates consist of a few simple tasks. The following example illustrates how to create and use a delegate of a function that takes string and returns void.
1. Declare a prototype of a “pointer to a function that takes string and returns void” as a pure virtual class with one member function:
class StringDelegate { public: virtual void runTheFunction(string params) = 0; };
2. Implement your specific callback function
The callback function’s implementation is a class that inherits from StringDelegate. Optionally, it would be nicer if it contained some kind of a “Runner” class that is responsible to handle the received data. The code follows:
class OurDelegate : public StringDelegate { public: void runTheFunction(string data); // Implementation! OurDelegate(Runner& runner); // The constructor should get the runner private: OurDelegate(); // No default constructor Runner m_runner; }; // The constructor OurDelegate::OurDelegate(Runner& runner):m_runner(runner) { } // The actual implementation void OurDelegate::runTheFunction(string data) { m_runner.run(data); } Now we can write the code that's calling our "callback function": void callme(StringDelegate sd) { sd.runTheFunction("Tralala"); }
Running the delegates is simple:
callme(OurDelegate(runner));
No pointers needed! Now that’s C++.