Link to Home page Main Banner


Local Links

RTEMS Ports

C/C++

CORBA

Java

Components

eCos

  

Motivation

Development of a Callback mechanism for C++ which must be simple and portable. An important goal is "easy to use" with all major C++ compilers available.

Callback Definition

A callback is a function, provided by a client to a subsystem, that allows that subsystem to perform a specific operation in the context of the client.

Callbacks are a powerful tool for breaking dependencies between cooperative classes. They can be extremely useful in an event driven design such as graphical user interface framework. Another area where callbacks are useful is for decoupling of the businees logic of an application from its user interface.

The indiscriminate use of callbacks can lead to designs that are difficult to understand, debug and maintain. Their ( pseudo ) asynchrous behavior requires a different type of attention from the developers.

For a more detailed description of callbacks and its use, check this book:

Large-Scale C++ Sofrware Design
by: John Lakos - Addison Wesley
ISBN: 0-201-63362-0

NOTE: The definition used here was based on the Callback section of John's book.

Class Diagram

The UML Class Diagram below show the relationships of the C++ callback framework. This framework is probably the most simpler of its kind. It allows clients to define callbacks either as global functions, static methods, or methods of classes. A method of a class can be virtual when used as a callback.

A callback is templated on the type of parameter used by the client and the subsystem involved. This "parameter type" will be the unique contract between the parts. For callbacks using member functions, they are also templated on the type of class involved.

It is important to have a good policy about the "parameter type" passd in with the notifications. We recommend to let the subsystem to handle the creation/deletion of it. This means that the invoker of a callback, in someway gets the parameter to pass in, makes the call and after the call is complete, it is responsible for getting rid of it. If the client needs to keep a copy of the data passed in, it must make a copy of it. This policy varies from project to project, but it is good to be very clear early on.


Fig. 1 - Class Diagram

CallbackContainers should be used for multi-cast notifications to multiple clients. It should be used with care on a multi-threaded environment.

Policy on Creation/Deletion

It is important to establish early on the policy for creation and deletion of the callback instances. Defining who will be responsible for deletion of the instances, and when that happens must be clear for the whole team. Usually, there are two scenarios for using callbacks:
  • One shot callbacks.
    A client provides a callback to a subsystem, and eventually it is invoked back sometime later. If the client needs to be notified again, it must provide the subsystem with another instance.
    With these types of scanarios, it is a good idea to let the caller subsystem to delete the callback once it completes the executation of it.
  • Multiple shots callbacks
    A client wants to be notified of one event as many times as it happens. In this case, it is a good idea to add an interface to the subsystem allowing clients to register for events. When a client decides not to be notified anymore, it would use the interface to deregister the callback. With this scenario, the invoker should keep the instance until it is told to "stop". The callback would be deleted during the de-registration process.

The important thing is that this policy should be clear and documented to the team. Every new member should know it early on.

Return Value

Return value in callbacks make not much sense. It is there for some application that might need some confirmation back. This always can be done adding extra attributes to the parameter involved. If you do not use the return value, return 0.

Examples

This section briefly describes the examples that comes with the test code provided with the Callback framework. Check the test directory in the distribution for a complete example on how to use this framework.

  • Callbacks as Global Functions
  • Assume that you have a global function as defined below,

    int bar( int * p )
    {
        printf( "global bar( %d )\n", ++(*p) );
        return 1;
    }

    Creating a callback instance that relying on the global function above is as easy as doing this:

    FunctionCallback< int > f( bar );

    Invoking the callback is as easy as doing this:

        int x = 3;
        f.notify( &x );

  • Callbacks as Member Functions ( methods )
  • Let's define a class with a virtual method which we intend to use it as a callback:

    class FooBase
    {
    public:
        FooBase() { printf( "Ctor FooBase()\n" ); }
        ~FooBase() { printf( "Dtor FooBase()\n" ); }
        virtual int foo( int * p )
        {
            printf( "foo base( %d )\n", ++(*p) );
            return 1;
        }
    };

    Creating a callback instance that relies on this member function is as easy as doing this:

    FooBase b;
    MemberCallback< int, FooBase > c( &FooBase::foo, &b );

    Invoking the callback is as easy as doing this:

        int x = 3;
        c.notify( &x );

For a complete test driver of the callback framework, see the test directory which is part of the distribution.

Download

callback-1.01.zip
Archive with source code and examples of the callback framework.

License

This framework is licensed under the LGPL.

Visitors:



Last modified Apr 27, 2000
Copyright ©1999-2000 Rosimildo da Silva. All rights reserved.


   e-mail me