Generalized Callbacks: C++ and C#
by William F. Humphrey

Listing One
/* Define the callback function */
float callback(int, double) { /* function body */ }
int main(int argc, char *argv[]) {
  /* Create a variable to store a reference to the callback */

  typedef float (*CallbackRef)(int, double);
  CallbackRef cb;
  /* Register the callback function for later invocation */
  cb = &callback;
  /* Invoke the callback function with arguments */
  cb(1, 2.0);
}


Listing Two
// The abstract callback interface
class CallbackInterface {
public:
  // The target callback function
  virtual int callback(int, double) = 0;
};
// An implementation of the interface
class CallbackImpl : public CallbackInterface {
public:
  virtual int callback(int, double) {
    std::cout << "Callback invoked" << std::endl;
    return 0;
  }
};
// A class that stores a target callback reference and invokes it 
// later using operator()
class CallbackContainer {
public:
  CallbackContainer(CallbackInterface *c) : cb_m(c) { }
  void operator()(int a, double b) { cb_m->callback(a, b); }
private:
  CallbackInterface *cb_m;
};
int main(int argc, char *argv[]) {
  // Declare a callback container and add a reference
  CallbackContainer cb(new CallbackImpl());
  // Invoke the callback after doing some work
  cb(1, 2.0);
}


Listing Three
typedef SigC::Signal2<float, int, double> SampleSignal_t;
class SampleClass {
public:
  SampleSignal_t signalobj;
};


Listing Four
// A global function callback
float callback(int, double) { /* function body */ }
// A class with instance method callbacks
class SampleCB : public SigC::Object {
public:
  float method(int, double) { /* body */ }
};
// Connect callbacks to the signal from Listing 3
int main(int argc, char *argv[]) {
  SampleClass sample;
  SampleCB target;
  // Connect a global function
  sample.signalobj.connect(SigC::Slot2<float,int,double>(callback));
  // Connect a method using 'slot' utility function, noting connection
  SigC::Connection connection =
    sample.signalobj.connect(slot(target, &SampleCB::method));
  // Emit the signal, calling 'callback' and 'method'
  sample.signalobj.emit(1, 2.0);
  // Disconnect the second callback then emit the same signal;
  // this will only invoke 'callback'
  connection.disconnect();
  sample.signalobj.emit(2, 2.0);
}


Listing Five
public delegate float SampleDelegate(int a, double b);
public class SampleClass {
  public SampleDelegate delegateobj = null;
}


Listing Six
// A class with static and instance method callbacks
public class SampleCB {
  public static float callback(int a, double b) { return 1.0F; }
  public float method(int a, double b) { return 2.0F; }
};
// Connect callbacks to the delegate from Listing 5
public class MainClass {
  public static void Main(string[] args) {
    SampleClass sample = new SampleClass();
    // Connect a static method to the delegate in sample
    sample.delegateobj += new SampleDelegate(SampleCB.callback);
    // Connect an instance method to the delegate
    SampleCB target = new SampleCB();
    sample.delegateobj += new SampleDelegate(target.method);
    // Invoke the delegate, calling 'callback' and 'method'
    sample.delegateobj(1, 2.0);
    // Disconnect the second callback then invoke the delegate again;
    // this will only invoke 'SampleCB.callback'
    sample.delegateobj -= new SampleDelegate(target.method);
    sample.delegateobj(2, 2.0);
  }
}


Listing Seven
// A new Marshal class
template<class T>
class EqualZeroMarshal {
public:
  typedef T InType;
  typedef int OutType;
  OutType value()
  {
    return result_m;
  }
  static OutType default_value()
  {
    return 0;
  }
  // If this returns true, no more callbacks will be called.
  bool marshal(const InType &in)
  {
    if (in == 0)
      result_m++;
    return false;
  }
  EqualZeroMarshal() : result_m(0) { }
private:
  OutType result_m;
};
// Create a Signal using this marshaller.
SigC::Signal1<bool,float,EqualZeroMarshal<bool> > signalobj;





3


