Callback functions in C++

Viewed 574770

In C++, when and how do you use a callback function?

EDIT:
I would like to see a simple example to write a callback function.

11 Answers

There is also the C way of doing callbacks: function pointers

// Define a type for the callback signature,
// it is not necessary but makes life easier

// Function pointer called CallbackType that takes a float
// and returns an int
typedef int (*CallbackType)(float);

void DoWork(CallbackType callback)
{
  float variable = 0.0f;
  
  // Do calculations
  
  // Call the callback with the variable, and retrieve the
  // result
  int result = callback(variable);

  // Do something with the result
}

int SomeCallback(float variable)
{
  int result;

  // Interpret variable

  return result;
}

int main(int argc, char ** argv)
{
  // Pass in SomeCallback to the DoWork
  DoWork(&SomeCallback);
}

Now, if you want to pass in class methods as callbacks, the declarations to those function pointers have more complex declarations, for example:

// Declaration:
typedef int (ClassName::*CallbackType)(float);

// This method performs work using an object instance
void DoWorkObject(CallbackType callback)
{
  // Class instance to invoke it through
  ClassName objectInstance;

  // Invocation
  int result = (objectInstance.*callback)(1.0f);
}

//This method performs work using an object pointer
void DoWorkPointer(CallbackType callback)
{
  // Class pointer to invoke it through
  ClassName * pointerInstance;

  // Invocation
  int result = (pointerInstance->*callback)(1.0f);
}

int main(int argc, char ** argv)
{
  // Pass in SomeCallback to the DoWork
  DoWorkObject(&ClassName::Method);
  DoWorkPointer(&ClassName::Method);
}

Scott Meyers gives a nice example:

class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);

class GameCharacter
{
public:
  typedef std::function<int (const GameCharacter&)> HealthCalcFunc;

  explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
  : healthFunc(hcf)
  { }

  int healthValue() const { return healthFunc(*this); }

private:
  HealthCalcFunc healthFunc;
};

I think the example says it all.

std::function<> is the "modern" way of writing C++ callbacks.

A Callback function is a method that is passed into a routine, and called at some point by the routine to which it is passed.

This is very useful for making reusable software. For example, many operating system APIs (such as the Windows API) use callbacks heavily.

For example, if you wanted to work with files in a folder - you can call an API function, with your own routine, and your routine gets run once per file in the specified folder. This allows the API to be very flexible.

There isn't an explicit concept of a callback function in C++. Callback mechanisms are often implemented via function pointers, functor objects, or callback objects. The programmers have to explicitly design and implement callback functionality.

Edit based on feedback:

In spite of the negative feedback this answer has received, it is not wrong. I'll try to do a better job of explaining where I'm coming from.

C and C++ have everything you need to implement callback functions. The most common and trivial way to implement a callback function is to pass a function pointer as a function argument.

However, callback functions and function pointers are not synonymous. A function pointer is a language mechanism, while a callback function is a semantic concept. Function pointers are not the only way to implement a callback function - you can also use functors and even garden variety virtual functions. What makes a function call a callback is not the mechanism used to identify and call the function, but the context and semantics of the call. Saying something is a callback function implies a greater than normal separation between the calling function and the specific function being called, a looser conceptual coupling between the caller and the callee, with the caller having explicit control over what gets called. It is that fuzzy notion of looser conceptual coupling and caller-driven function selection that makes something a callback function, not the use of a function pointer.

For example, the .NET documentation for IFormatProvider says that "GetFormat is a callback method", even though it is just a run-of-the-mill interface method. I don't think anyone would argue that all virtual method calls are callback functions. What makes GetFormat a callback method is not the mechanics of how it is passed or invoked, but the semantics of the caller picking which object's GetFormat method will be called.

Some languages include features with explicit callback semantics, typically related to events and event handling. For example, C# has the event type with syntax and semantics explicitly designed around the concept of callbacks. Visual Basic has its Handles clause, which explicitly declares a method to be a callback function while abstracting away the concept of delegates or function pointers. In these cases, the semantic concept of a callback is integrated into the language itself.

C and C++, on the other hand, does not embed the semantic concept of callback functions nearly as explicitly. The mechanisms are there, the integrated semantics are not. You can implement callback functions just fine, but to get something more sophisticated which includes explicit callback semantics you have to build it on top of what C++ provides, such as what Qt did with their Signals and Slots.

In a nutshell, C++ has what you need to implement callbacks, often quite easily and trivially using function pointers. What it does not have is keywords and features whose semantics are specific to callbacks, such as raise, emit, Handles, event +=, etc. If you're coming from a language with those types of elements, the native callback support in C++ will feel neutered.

The accepted answer is comprehensive but related to the question i just want to put an simple example here. I had a code that i'd written it a long time ago. i wanted to traverse a tree with in-order way (left-node then root-node then right-node) and whenever i reach to one Node i wanted to be able to call a arbitrary function so that it could do everything.

void inorder_traversal(Node *p, void *out, void (*callback)(Node *in, void *out))
{
    if (p == NULL)
        return;
    inorder_traversal(p->left, out, callback);
    callback(p, out); // call callback function like this.
    inorder_traversal(p->right, out, callback);
}


// Function like bellow can be used in callback of inorder_traversal.
void foo(Node *t, void *out = NULL)
{
    // You can just leave the out variable and working with specific node of tree. like bellow.
    // cout << t->item;
    // Or
    // You can assign value to out variable like below
    // Mention that the type of out is void * so that you must firstly cast it to your proper out.
    *((int *)out) += 1;
}
// This function use inorder_travesal function to count the number of nodes existing in the tree.
void number_nodes(Node *t)
{
    int sum = 0;
    inorder_traversal(t, &sum, foo);
    cout << sum;
}

 int main()
{

    Node *root = NULL;
    // What These functions perform is inserting an integer into a Tree data-structure.
    root = insert_tree(root, 6);
    root = insert_tree(root, 3);
    root = insert_tree(root, 8);
    root = insert_tree(root, 7);
    root = insert_tree(root, 9);
    root = insert_tree(root, 10);
    number_nodes(root);
}

@Pixelchemist already gave a comprehensive answer. But as a web developmer, I can give some tips.

Usually we use tcp to develop a web framework, so usually we have a structure:

TcpServer listen port and register the socket to epoll or something
  -> TcpServer receive new connection 
    -> HttpConenction deal the data from the connection 
      -> HttpServer call Handler to deal with HttpConnection.
        -> Handler contain codes like save into database and fetch from db

We can develop the framework as the order, but it is not friendly to the user who only want to care the Handler. So it is time to use the callback.

Mutiple Handler written by user
  -> register the handler as callback property of HttpServer
    -> register the related methods in HttpServer to HttpConnection
      -> register the relate methods in HttpConnection to TcpServer

So user only need to register their handlers to httpserver(usually with some path string as key), the other thing is generic the framework can do.

So you can find we can treat the callback as a kind of context, that we want delegate to other to do for us. The core is that we don't know when is the best time to invoke the function, but the guy we delegate to know.

Related