I l@ve RuBoard |
![]() ![]() |
5.3 C++ Callable EntitiesTo put together a generic implementation for forwarding commands, let's try to get Command-specific notions closer to terms familiar to C++ programming. A forwarding command is a callback on steroids, a generalized callback. A callback is a pointer to a function that can be passed around and called at any time, as illustrated in the following example. void Foo(); void Bar(); int main() { // Define a pointer to a function that takes no // parameters and returns void. // Initialize that pointer with the address of Foo void (*pF)() = &Foo; Foo(); // Call Foo directly Bar(); // Call Bar directly (*pF)(); // Call Foo via pF void (*pF2)() = pF; // Create a copy of pF pF = &Bar; // Change pF to point to Bar (*pF)(); // Now call Bar via pF (*pF2)(); // Call Foo via pF2 } There is an essential difference between calling Foo and calling (*pF).[1] The difference is that in the latter case you can copy and change pointers to functions. You can take a pointer to a function, store it somewhere, and call it when the right time comes—hence, the similarity with forwarding Commands, which are essentially a piece of work that is stored away from its actual executor and processed later.
In fact, callbacks are the C way of using the Command pattern in many windowing systems. X Windows, for instance, stores such a callback in each menu item and in each widget. The widget calls the callback when the user does something (like clicking on the widget). The widget does not know what the callback actually does. In addition to simple callbacks, C++ defines many more entities that support the function-call operator. Let's enumerate all the things that support operator() in C++.
You can add a pair of parentheses to the right of any of the enumerated items, put an appropriate list of arguments inside, and get some processing done. No other objects in C++ allow this except the ones just listed. The objects that support operator() are known as callable entities. The goal of this chapter is to implement a set of forwarding commands that store and can forward a call to any callable entity.[2] The Functor class template will encapsulate the forwarding commands and provide a uniform interface.
The implementation must handle the three essential cases: simple function calls, functor calls (including Functor calls; that is, you should be able to forward calls from one Functor to another), and member function calls. You might think to define an abstract base class and create a subclass for each case. All this sounds like straightforward C++. As you launch your favorite editor and start to type, however, an abundant crop of problems appears. ![]() |
I l@ve RuBoard |
![]() ![]() |