Method pointers

Top  Previous  Next

What is translated > Method pointers

Delphi's event handling is implemented by means of method pointers. Such  method pointers are declared by addition of the words "of object" to a procedural type name. E.g.

 

TNotifyEvent = procedure(Sender: TObject) of object;

 

According to the Delphi help "a method pointer is really a pair of pointers; the first stores the address of a method, and the second stores a reference to the object the method belongs to". Such method pointers can point to any member functions in any class. For example by means of a method pointer  the event handling of a special instance of a control - e.g. TButton - can be delegated to the instance of another class - e.g. TForm .

 

Delphi's method pointers cannot be translated as standard C++ member function pointers, because they can point to other member functions of the same inheritance hierarchy only. That's why Borland has extended the standard C++ syntax by the keyword __closure. With this keyword method pointers with the same properties as Delphi's method pointers can be declared in Borland C++. E.g. the event above is:

 

typedef void __fastcall (__closure *TNotifyEvent)(TObject* Sender);

 

For other compilers than  C++Builder d2c::event provides a small, single-cast delegate with Delphi-like behavior:

 

Type-safe: d2c::event<R(Args...)> matches the procedure/function signature.
Non-owning binding: stores the target object pointer plus a callable.
Null/empty checks: if (ev) ev(...);
Equality: ev1.equals(ev2) (same object and same bound member).
Reset: ev.reset() clears the binding.

 

Quick mapping

 

Delphi “of object” event

 

type

  TNotifyEvent = procedure(Sender: TObject) of object;

 

type

  TMyButton = class

  public

    OnClick: TNotifyEvent;

  end;

 

 

C++ (with d2c_event.h)

 

// alias the event type

typedef d2c::event<void(System::TObject*)> TNotifyEvent;

 

class TMyButton : public System::TObject 

{

public:

  TNotifyEvent OnClick;

 

  void FireClick(System::TObject* sender) 

  {

    if (OnClick) 

     OnClick(sender);        // null-safe invoke

  }

};

 

Binding a handler (member method)

 

class TFormMain : public System::TObject {

public:

  void ButtonClick(System::TObject* Sender);

};

 

TMyButton* Button1 = /* ... */;

TFormMain* Form1   = /* ... */;

 

Button1->OnClick = d2c::bind(Form1, &TFormMain::ButtonClick);

 

 

d2c::bind(obj, &Class::Method) creates a bound event.

 

The object must outlive all calls to the event (non-owning).

 

Calling, reassigning, clearing

 

Button1->FireClick(Button1);            // call if assigned

Button2->OnClick = Button1->OnClick;    // copy/assign another handler

Button2->OnClick.reset();               // clear

 

Comparing two events

 

bool same = Button1->OnClick.equals(Button2->OnClick);

// true only if both reference the *same instance* and the *same member function*

 

Arrays / tables of events

 

Delphi often stores “procedure of object” values in arrays. That translates 1:1:

 

std::array<d2c::event<void()>, 256> handlers;

 

// assign

handlers['A'] = d2c::bind(this, &TMyClass::OpenProc);

// call (null-safe check is recommended)

if (handlers['A']) handlers['A']();

 

 

 

 

 

 

 

 

 



This page belongs to the Delphi2Cpp Documentation

Delphi2Cpp home  Content