
ns-3 Manual, Release ns-3.12
int result = pfi (1234);
Notice that the function pointer obeys value semantics, so you can pass it around like any other value. Typically, when
you use an asynchronous interface you will pass some entity like this to a function which will perform an action and
call back to let you know it completed. It calls back by following the indirection and executing the provided function.
In C++ you have the added complexity of objects. The analogy with the PFI above means you have a pointer to a
member function returning an int (PMI) instead of the pointer to function returning an int (PFI).
The declaration of the variable providing the indirection looks only slightly different:
int (MyClass::
*
pmi) (int arg) = 0;
This declares a variable named pmi just as the previous example declared a variable named pfi. Since the will be to
call a method of an instance of a particular class, one must declare that method in a class:
class MyClass {
public:
int MyMethod (int arg);
};
Given this class declaration, one would then initialize that variable like this:
pmi = &MyClass::MyMethod;
This assigns the address of the code implementing the method to the variable, completing the indirection. In order to
call a method, the code needs a this pointer. This, in turn, means there must be an object of MyClass to refer to. A
simplistic example of this is just calling a method indirectly (think virtual function):
int (MyClass::
*
pmi) (int arg) = 0; // Declare a PMI
pmi = &MyClass::MyMethod; // Point at the implementation code
MyClass myClass; // Need an instance of the class
(myClass.
*
pmi) (1234); // Call the method with an object ptr
Just like in the C example, you can use this in an asynchronous call to another module which will call back using a
method and an object pointer. The straightforward extension one might consider is to pass a pointer to the object and
the PMI variable. The module would just do:
(
*
objectPtr.
*
pmi) (1234);
to execute the callback on the desired object.
One might ask at this time, what’s the point? The called module will have to understand the concrete type of the calling
object in order to properly make the callback. Why not just accept this, pass the correctly typed object pointer and
do object->Method(1234) in the code instead of the callback? This is precisely the problem described above.
What is needed is a way to decouple the calling function from the called class completely. This requirement led to the
development of the Functor.
A functor is the outgrowth of something invented in the 1960s called a closure. It is basically just a packaged-up
function call, possibly with some state.
A functor has two parts, a specific part and a generic part, related through inheritance. The calling code (the code that
executes the callback) will execute a generic overloaded operator () of a generic functor to cause the callback to
be called. The called code (the code that wants to be called back) will have to provide a specialized implementation
of the operator () that performs the class-specific work that caused the close-coupling problem above.
With the specific functor and its overloaded operator () created, the called code then gives the specialized code
to the module that will execute the callback (the calling code).
3.2. Callbacks Background 13