www.digitalmars.com         C & C++   DMDScript  

D - callbacks/pointers to member functions

reply "Patrick Down" <pdown austin.rr.com> writes:
I've been thinking about pointers to member functions.  In
C++ they are very messy.  However you doo need methods of
defining callbacks from one object to another.

Interfaces come close to helping in this situation.

interface ClsACallback
{
  void SomeEvent();
}

class A
{
  SetCallback(ClsACallback cb)
  {
  }
}

class B : ClsACallback
{
  A theA;

  Init()
  {
    theA = new A;

    theA.SetCallback(this);
  }

  void SomeEvent()
  {
    // Handle event
  }
}

But what about the situation where you have multible
event producers of the same type that need different
handlers?

class B
{
  A theA1;
  A theA2;
  A theA3;

  Init()
  {
    theA1 = new A;
    theA3 = new A;
    theA3 = new A;

    // How do we set up the callbacks now?

  }

  void SomeEventFromTheA1()
  {
    // Handle event from A1
  }
  void SomeEventFromTheA2()
  {
    // Handle event from A2
  }
  void SomeEventFromTheA3()
  {
    // Handle event from A3
  }
}


In C++ we might use pointers to member functions.

  theA1->SetCallback(this,B::SomeEventFromTheA1);

Or you might pass a static function.

  theA1->SetCallback(this,RedirFuncTheA1);

  // Somewhere else
  void RedirFuncTheA1(B theB)
  {
    theB->SomeEventFromTheA1();
  }

Java solves this problem with inner classes.

I have one other solution I call named vtables.
Instead of defining that a class has just one
interface by inheritance you allow multiple
implemetations of that iterface and give them
different names.


class B
{
  A theA1;
  A theA2;
  A theA3;

  Init()
  {
    theA1 = new A;
    theA3 = new A;
    theA3 = new A;

    theA1.SetCallback(clsA1CB);
    theA2.SetCallback(clsA2CB);
    theA3.SetCallback(clsA3CB);

  }

  // Create an interface ClsACallback vtable for class B
  // called clsA1CB
  ClsACallback clsA1CB
  {
    void SomeEvent()
    {
      // Handle event from A1
    }
  }

  // Create an interface ClsACallback vtable for class B
  // called clsA1CB
  ClsACallback clsA2CB
  {
    void SomeEvent()
    {
      // Handle event from A2
    }
  }

  // Create an interface ClsACallback vtable for class B
  // called clsA1CB
  ClsACallback clsA3CB
  {
    void SomeEvent()
    {
      // Handle event from A3
    }
  }
}
Feb 07 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Patrick Down" <pdown austin.rr.com> wrote in message
news:a3v6j9$153f$1 digitaldaemon.com...
 I've been thinking about pointers to member functions.  In
 C++ they are very messy.  However you doo need methods of
 defining callbacks from one object to another.

I've had a leeeeeeengthy discussion with Walter on the topic already, see earlier on the newsgroup =)
 I have one other solution I call named vtables.
 Instead of defining that a class has just one
 interface by inheritance you allow multiple
 implemetations of that iterface and give them
 different names.

A very interesting idea that I also had. However, currently the way D handles casting class to interface (for details see _d_interface_vtbl() in cast.d in Phobos), two interfaces with the same classinfo - which happens in your case - cannot coexist in a single class. Well they can, but the first one will always be selected.
Feb 08 2002
parent Patrick Down <pat codemoon.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in news:a40j59$1oqv$1
 digitaldaemon.com:

 "Patrick Down" <pdown austin.rr.com> wrote in message
 news:a3v6j9$153f$1 digitaldaemon.com...
 I've been thinking about pointers to member functions.  In
 C++ they are very messy.  However you doo need methods of
 defining callbacks from one object to another.

I've had a leeeeeeengthy discussion with Walter on the topic already, see earlier on the newsgroup =)
 I have one other solution I call named vtables.
 Instead of defining that a class has just one
 interface by inheritance you allow multiple
 implemetations of that iterface and give them
 different names.

A very interesting idea that I also had. However, currently the way D handles casting class to interface (for details see _d_interface_vtbl() in cast.d in Phobos), two interfaces with the same classinfo - which happens in your case - cannot coexist in a single class. Well they can, but the first one will always be selected.

Yes after looking over cast.d I see why interfaces of the same type can't coexist in the interfaces list. However it seems like you could treat named vtables as a different mechanism, more like a static class variable.
Feb 08 2002