I believe that friends who have used Borland Delphi or C Builder should have a deep impression on the event callback mechanism in the VCL component, and the VCL component uses the event attribute to simplify the interaction between the class, improve the efficiency of the VCL component development program. At the same time, it is also possible to increase the event attribute in the class you have written, making the interaction with the VCL component or other custom classes simple and intuitive.
The event mechanism of the VCL is actually in a form of a function pointer callback, and the class A can directly call the instance method of class B directly by saving its class B instance method pointer in a class A. Just Borland's packaging from the development language level is easy to understand and ease. Such as follows:
// Declare an event type, which is equivalent to the function pointer type in C , just "of object", this type is a class method.
TerrorNotifyEvent = Procedure (Errcode: integer; errmsg: string) of object;
TsourceClass = Class (TOBJECT) / / Assume that TsourceClass needs to notify other classes to other classes
Private
/ / We can declare a member variable of a TERRORNOTIEVENT type for saving a callback function pointer
FONERROR: TERRORNOTIFYEVENT;
protected
Procedure doerrorNotify (Errcode: Integer, Errmsg: String);
public
// Declare the event properties and access through the Fonerror member variable
Property OneRror: TerrorNotifyEvent Read Fonerror Write Fonerror;
END;
Procedure TsourceClass.DoerrorNotify (Errcode: Integer, Errmsg: String);
Begin
If Fonerror <> nil the fonderror (errorcode, errmsg); // Toned the method pointer saved in Tsrouceclass.
END;
In this way, other classes can achieve the purpose of using the TsourceClass error report by accessing the TsourceClass class's OneRROR attribute. Once there is any error inside TsourceClass, you need to notify the outside, you can call DOERRORNOTIFY directly.
TtargetClass = Class (TOBJECT) / / Assume TtargetClass to need TSOURCLASS error notification
Private
public
// Declare a member method that is compatible with TerrorNotifyEvent type
Procedure ReceiveErrorNotify (Errorcode: Integer; Errmsg: String);
END;
Procedure TtargetClass.ReceiveErrorNotify (ERRMSG: String);
Begin
// Dissive from the TSOURCLASS error notification in ReceiveErrorNotify
END;
In this way, both TsourceClass and TtargetClass have everything that interacts with the TERRORNOTIFYEVENT event type. The following code demonstrates how to contact between their instances.
Objsource: TsourceClass;
Objtarget: TtargetClass;
Objsource: = TsourceClass.create;
Objtarget: = TtargetClass.create;
Objsource.onerror: = objTarget.Receive // This will contact ObjSource with ObjTarget. Back to the VC that occupies an important position in C visualization, the MFC framework does not provide an event callback mechanism such as a VCL framework. Interaction between different classes requires many additional code, or other methods such as Window messages. If you use the MFC's CasyncSocket class, you have to overload certain methods to achieve the purpose of receiving Socket data. If the CasyncSocket itself has an event similar to the Socket data arriving, then we can do not need to overload the CasyncSocket class, and you can reach the purpose of receiving Socket data directly in the main program class.
So, do you have any other way to help realize similar VCL event callback mechanisms in the VC?
Refer to the above VCL example, we naturally think of the following ways:
TYPEDEF VOID (INT Notify_code); // Defines Event Tune Function Pointer Type
Class A
{
Private:
PUBLIC:
Notify_event onnotify; // Declare event properties
}
Class B
{
Private:
PUBLIC:
Void ReceiveNotify / / Define Member Functions for Receive Tune Notifications
{
}
}
And use as follows:
A Obja;
B Objb;
Obja.onnotify = objb.receivenotify; // The connection between the class instance, but this statement compiles an error!
Compiled in VC, it will generate the following compilation error
Error C2440: '=': Cannot Convert from 'Void (_thiscall B :: *) (int)' to 'void (__cdecl *) (int) "
The above compilation information indicates two points:
1. The ONNOTIFY member variable of class A is different from the call mode of NOTIFY_EVENT and B :: ReceiveNotify. The former is the __cdecl mode, the latter is the default thiscall method;
2. Notify_event is different from the B :: ReceiveNotify type, the former is a general function pointer type, the latter is a function pointer type for class B.
Member pointer
As the name implies, it is directed to the pointer to the members. The definition and use of member pointers is supported in C . Such as:
Class A
{
PUBLIC:
INT m_INTMEMBER;
Void voidMethod () {}
}
There is a M_Intmember member variable in class A, a VoidMethod member function. We can declare and use members pointers to them:
INT A :: * Pint = & a :: m_intmember;
TYPEDEF (B :: * Method_Pointer) ();
Method_Pointer Pmethod = & b :: voidMethod;
A Obja; a objb;
INT IVAR = Obja. * pint; // Direct access to instance Obja's m_intmember value
Obja. * pmethod (); // Calling is an instance Obja's voidMethod method
Objb. * Pint = Ivar; // Direct access to instance Objb's m_intmember value
Objb. * pmethod (); // Calling is an instance Objb's VoidMethod method
So how do we use member pointers to solve the problem of above compilation errors? Please see the following code. // Declare a function pointer type for class B
Typedef void (b :: * error_notify_event) (int notify_code);
Class A
{
Private:
PUBLIC:
ERROR_NOTIFY_EVENT ONNOTIFY;
}
Class B
{
Private:
PUBLIC:
Void ReceiveNotify (int notify_code)
{
}
}
A Obja;
B Objb;
Obja.onnotify = objb.receivenotify; // This is OK! ! !
By declaring member function pointer type type type typef void (b :: * error_notify "(int notify_code), implementing the class A instance callback class B instance, which is a method of implementing an event callback mechanism in C .