A system method for establishing an inter-object message connection in C
Item
Users who have used C over-object-oriented programming are known, and the objects in the program rarely exist. Almost impossible to consider the interaction between the objects. Therefore, identifying the relationship between the object or the message connection between the establishment of the object is an important task for object-oriented programming. This paper focuses on the perspective of C programming, proposes a practical method for establishing a message connection between an object. If you want to learn more about the object programming technology in detail, please refer to the monograph. Everyone knows that the object is a package of data and methods. In C , they behave separately as data members and member functions. Program designers change the status of the object by performing the various methods of the object (ie, change the properties data of the object). This makes some "events" in this object. When an object occurs an event, it usually needs to send "messages" to other related objects, requesting them to make some processing. At this time, an event occurs and processed to other objects is called an "event object", and the object of the handling event is called "callback object". The processing of the callback object is called "callback function". In C , this process is equivalent to: When an event object occurs, call some member functions of the callback object. The usual method is to transfer the object pointer to the event object to the event object. But this method is not universal. In order to reduce the workload of programming, this paper proposes a system method for establishing a message connection between an object. Its idea is: Abstract "Events → Request Handling → Perform Processing" into a "callback" class. By inheritance, users can easily obtain the mechanism of establishing a message connection between the object.
First, the data structure of the callback class and its member functions
The Callback class proposed in this article supports three callback functions. They are: the member function in the callback object, belongs to the static member function of the callback class and the normal C function. The Callbackle class contains a modular function table CallbackList. It is used to record the event name, pointing to the pointer to the callback function and the callback object. Each node of the table is an event record EventRecord. Each event record contains three domains: Event Name Pointer EventName, pointer Pointertocbo, pointing to the callback object Pointertocbf or Pointertocbsf (where Pointertocbf points to the member function of the callback object, Pointertocbsf points to the static member function of the callback class or ordinary Function. They are in a usual use body). The callback mechanism provided by the Callback class is this: the callback function in the registration of the callback object is registered on the event object; when the event occurs, the event object retrieves and executes the callback function in its callback table. This makes the message connection of the two. (About the specific implementation of this class, please refer to the list of procedures attached to the article) Tune Object Event Object Event Name Tune Object Pointer Pointer Pointer
"Event" Pointercbo Pointertocbf or
Pointertocbsf
- - - - - ADDCALLBACK: Register event name and point to the callback function, the pointer of the callback object CallCallback: In the callback table, retrieve the registration to the callback function on the specified event and call the event, call the callcallback function to process event Event. Member functions inherited from the callback of the Callback class CallbackList, member functions AddCallback and CallCallback. Pointertocbo is NULL when the callback function is a static member function or a normal C function. The event name is the retrieval key in callback, CallbackLis. Other member functions in the callback object
The member function addCallback class of the Callback class is used to register the callback function into the callback table of the event object. It has two overload versions:
Void Callback :: AddCallback (Char * Event, Callback * P); Void Callback :: AddCallback (Char * Event, CallbackStaticFunction CBSF);
Among them, the first addCallback is used to register a member function of a callback object to the callback table of the event object. The second addCallback is used to register or call the static member function of a call to register in the callback table of the event object. In the top parameter table, Event is a pointer to the event name string, and P is a pointer to the callback object, and the CBF and CBSF are pointers that point to member functions and static member functions (or ordinary functions). When the callback function from a callback object SomeObject, transfer member function pointer should be formatted as follows: (CallBackFunction) & SomeObject :: MemberFunctionName; transmitting a static class member function pointer SomeObject format should be used: (CallBackStaticFunction) & SomeObject :: FunctionName; transfer When a normal function pointer is a general function pointer, you only need to pass a function name.
The member function void callback :: CallCallback (char * ename, calldata calldata = null) is used to call all callback functions registered on the event ename. Among them, CallData is a data pointer (CallData is actually void *, see a list of procedures). Event objects can pass useful data to the callback object. The member function is typically called in the member function of the event object, as usual only if the member function of the event object can change the internal data of the object, thereby causing some events.
Member function RemoveCallback is used to delete the callback function registered on the event object. Its three overload versions are:
Void Callback :: RemoveCallback (Char * Event, CallbackFunction CBF, Callback * P);
Void Callback :: RemoveCallback (Char * Event, CallbackStaticFunction CBSF);
Void Callback :: RemoveCallback (Char * Event);
Among them, Event, CBF, CBSF, P or other parameters are the same as the member function addCallback. The first RemoveCallback is used to delete a member function that registers a callback object on the event Event. The second RemoveCallback is used to delete a static member function that registers a normal function or a tempering class on an event Event. The third REMOVALLBACK is used to delete all the callback functions registered on the event EVENT.
Second, the use of the Callback class
With the Callback class, you can do it as follows:
1. Determine which objects in the program have a relationship, requiring a message connection. And determine which object is an event object in each particular message connection relationship, which object is a callback object.
2. Event object classes and callback object classes must be inherited from the Callback class to get a callback support.
3. Register the callback data for the event object. Including: event name, callback function name, pointing to the pointer to the callback object.
4. When you are interested in incident, call the CallCallback function in the member function of the event object class.
Here is a specific example. By it will learn more about the use of the Callback class.
File: // Test Program File: Test.cpp
#include "callback.h" file: // "Speaker" class
Class Speaker: Public Callback
{
Private:
Int Volume;
PUBLIC:
Speaker (INT V): Volume (V) {}
Void Increasevolume (int V) File: / / Add volume member function
{
Volume = V;
IF (Volume> 20) {file: // "Volume greater than 20" incident happened
File: // Call the callback function registered on the two events
CallCallback ("Volume change");
CallCallback ("Volume is greater than 20", & volume);
}
}
Void DecreaseVolume (int V) file: / / reduce volume member function
{
Volume - = v;
IF (Volume <5) {file: // "The volume is less than 5" incident happened
File: // Call the callback function registered on the two events
CallCallback ("Volume change");
CallCallback ("The volume is less than 5", & volume);
}
}
}
File: // "Ear" class
Class Ear: Public Callback
{
PUBLIC:
Static Void Response (CallData CallData) file: // Reaction of "Volume Change"
{
Cout << "The volume changed." << Endl;
}
Void highvoiceresponse (calldata calldata) // Reaction to the treble
{
Cout << "Hey! Too noisy! The volume is:" << *) CallData) << ENDL;
}
Void LowVoicesResponse (CallData CallData) / / Reaction of Bass
{
Cout << "! I can't hear it. Now the volume is:" << *) CallData) << end1
}
}
Void main (void)
{
Speaker S (10); File: // Today's volume is 10
Ear e;
File: / / Register the callback function for the event object S
S.addCallback ("Volume greater than 20", (CallbackFunction) & Ear :: HighvoicesResponse, & E);
S.addCallback ("CallbackFunction) & Ear :: LowvoicesResponse, & E);
S.addCallback ("Volume Change", (CallbackStaticFunction) & Ear :: response);
S.incReasevolume (12); // increase the volume 12, now the volume bit 22
S.Decreasevolume (20); // Reduce volume 20, now volume bit 2
}
operation result:
The volume changed.
Hey! It's noisy! The volume is: 22
The volume changed.
what! I can't hear it. The volume is: 2
In the above example, the speaker object S is an event object, the ear object e is a callback object. . Some of the three events were registered: "The volume changed", "volume is greater than 20", "volume is less than 5". The callback function is: Ear :: Response, Ear :: Highvoiceerestsponse, Ear :: lowvoiceerestsponse. When the speaker S changes the volume through its member functions Increasevolume and DecReaseVolume, the callback object E will automatically react. It can be seen that the establishment of a message connection between the objects has become a simple and beautiful work by using the Callback class. Because the author's level is limited, the design of this class must be imperfect. If you are interested in it, the author can discuss such issues with you C players. Contact: fei_xiang@263.net
Attachment: Program list (this program is compiled in MS VC 5.0 and TC 3.0)
File: // Toned class structure: Callback.h
#ifndef _callback_h
#define _callback_h
#include
#include
#include
#define callbacklist_init_size 10
#define callbacklist_increment 5
Class Callback;
TypeDef void * calldata; // Tune Data Pointer Type Definition
TypeDef void (callback :: * callbackfunction); file: // Pointer to the callback member function
Typedef void (* callbackstaticfunction) (CallData); file: // Pointer type definition points to static member functions or normal functions
Class EventRecord {
Private:
Char * EventName; File: // Tonance Event Name
Callback * pointertocbo; // Pointer to the callback object
File: // Pointer to the member function and the common body pointing to a static member function (or a normal function) pointer
Union {
Callbackfunction Pointertocbf;
Callbackstaticfunction Pointertocbsf;
}
PUBLIC:
EventRecord (Void); File: // Event Record class default constructor
File: // Constructs an event record containing member functions
EventRecord (Char * ENAME, CALLBACK * PCBO, CallbackFunction PCBF);
File: // Constructs an event record containing static member functions or normal functions
EventRecord (Char * ENAME, CALLBACKSTACFUNCTION PCBSF);
~ EventRecord (void); // Destructure event record
Void Operator = (const eventRecord & ER); // Overloaded assignment operator
File: // Determine whether the current event record is ename
INT Operator == (char * ename) Const;
File: // Determine whether the current event record is equal to the specified event record
INT Operator == (Const EventRecord & Er) Const;
Void flush (void); file: // Clear the current event record
INT ISEMPTY (VOID) const; // Judgment Event Record is empty (ie, whether the event name is empty)
Friend Class Callback; File: / / Let the Callback class access to the private member of EventRecord;
Class callback {
Private:
EventRecord * CallbackList; File: // Toning incident table
INT Curpos; File: // Current event record location
INT LastPos; File: // The last idle location in the reconciliation table
INT size; file: // The size of the reconversion table
Void movefirst (void) {curpos = 0;} // set the current record as the first record
Void MoveNext (Void) file: // Place the next record as the current record
{
IF (curpos == lastpos) return;
Curpos ;
}
File: // Decision of the callback watch is traversed
INT endoflist (void) const {return curpos == lastpos;
PUBLIC:
Callback (void); // Constructor
Callback (const callback & cb); // copy constructor
~ Callback (void); // Destructor
Void Operator = (const callback & cb); // Overload assignment operator
File: // Put the member function of the callback object, static member function (or ordinary function)
File: // Register the callback function for the event object
Void AddCallback (Char * Event, CallbackFunction CBF, Callback * P);
Void AddCallback (Char * Event, CallbackStaticFunction CBSF);
File: // Delete the callback function registered on the specified event
Void RemoveCallback (Char * Event, CallbackFunction CBF, Callback * P);
Void RemoveCallback (Char * Event, CallbackStaticFunction CBSF);
Void RemoveCallback (Char * Event); // Delete all the records of an event
FILE: / / Perform all callback functions registered on a certain event
Void CallCallback (Char * Event, CallData CallData = NULL);
}
#ENDIF
File: // Realization of Call Tune: Callback.cpp
#include "callback.h"
File: // EventRecord class implementation
EventRecord :: EventRecord (Void)
{
Eventname = null;
Pointertocbo = NULL;
File: // Because Sizeof (CallbackFunction)> sizeof (CallbackStaticFunction)
Pointertocbf = NULL;
}
EventRecord :: EventRecord (Char * ENAME, CALLBACK * PCBO, CALLBACKFUNCTION PCBF)
: Pointertocbo (PCBO), Pointertocbf (PCBF)
{
Eventname = strDUp (ename);
}
EventRecord :: EventRecord (Char * ENAME, CALLBACKSTATICFUNCTION PCBSF)
: Pointertocbo (NULL), Pointertocbsf (PCBSF)
{
Eventname = strDUp (ename);
}
EventRecord :: ~ EventRecord (void) {
Eventname Delete EventName;
}
Void EventRecord :: Operator = (Const EventRecord & Er)
{
IF (er.eventname)
Eventname = strdup (er.eventname);
Else
Eventname = null;
Pointertocbo = Er.Pointertocbo;
Pointertocbf = Er.Pointertocbf;
}
Int EventRecord :: Operator == (Char * ENAME) Const
{
IF ((EventName == Null) || ENAME == NULL)
Return Eventname == ename;
Else
Return strcmp (eventname, eName) == 0;
}
INT EventRecord :: Operator == (Const EventRecord & Er) Const
{
Return (ER == EventName) / * Er and EventName cannot be swapped * /
&& (Pointertocbo == Er.Pointertocbo)
&& (Pointertocbo?
(Pointertocbf == Er.Pointertocbf):
(Pointertocbsf == Er.Pointertocbsf);
}
Void EventRecord :: Flush (void)
{
IF (eventname) {
Delete Eventname;
Eventname = null;
}
Pointertocbo = NULL;
Pointertocbf = NULL;
}
Int EventRecord :: ISempty (Void) Const
{
IF (eventname == null)
Return 1;
Else
Return 0;
}
File: // CallBack class implementation
Callback :: Callback (void)
{
File: // Allocate memory space by the initial size
Callbacklist = new evenetrecord [callbacklist_init_size];
IF (! CallbackList) {
CERR << "Callback: Memory Allocation Error." << endl;
Exit (1);
}
SIZE = CallbackList_init_size;
Lastpos = 0;
Curpos = 0;
}
Callback :: Callback (Const Callback & Cb): Curpos (Cb.Curpos), Lastpos (Cb.lastpos), Size (Cb.size)
{
Callbacklist = new eventRecord [size];
IF (! CallbackList) {
CERR << "Callback: Memory Allocation Error." << endl;
Exit (1);
}
File: // One copy of each event record
For (int i = 0; i } Void Callback :: Operator = (const callback & cb) { Curpos = cb.curpos; Lastpos = cb.lastpos; SIZE = Cb.size; Delete [] CallbackList; // Delete the old callback watch Callbacklist = new eventRecord [size]; // Reassign the memory space IF (! CallbackList) { CERR << "Callback: Memory Allocation Error." << endl; Exit (1); } File: // One copy of each event record For (int i = 0; i } Callback :: ~ Callback (void) { DELETE [] CallbackList; } Void Callback :: AddCallback (Char * Event, CallbackFunction PCBF, CALLBACK * PCBO) { File: // If the event is empty, exit IF ((Event == NULL)? 1: (Strlen (Event) == 0)) Return; File: // Look for the first idle position generated by deleting event records, and fill in new event records For (int start = 0; start IF (CallbackList [Start] .Isempty ()) { CallbackList [start] = EventRecord (Event, PCBO, PCBF); Break; } IF (start File: // No idle position, add new records after the callback watch IF (lastpos == size) file: // The callback watch is full, you need to "elongate" { EventRecord * Templist = CallbackList; // State the old callback pointer File: // Take a certain step "elongation" CallbackList = New EventRecord [Size CallbackList_Increment]; IF (! CallbackList) { CERR << "Callback: Memory Allocation Error." << endl; Exit (1); } File: // Copy the record in the old reconversion table For (int i = 0; i Delete [] templist; // Delete old reconvers Size = CallbackList_increment; // Remember the size of the new reconversion table } File: // Construct a new event record and fill it in the callback table Callbacklist [lastpos] = EventRecord (Event, PCBO, PCBF); LastPOS ; } Void Callback :: AddCallback (Char * Event, CallbackStaticFunction PCBSF) { IF ((Event == NULL)? 1: (Strlen (Event) == 0)) Return; For (int start = 0; start IF (CallbackList [start] .Isempty ()) {callbacklist [start] = event, pcbsf); Break; } IF (Start IF (LastPos == Size) File: // Event List is Insufficient { EventRecord * Templist = CallbackList; CallbackList = New EventRecord [Size CallbackList_Increment]; IF (! CallbackList) { CERR << "Callback: Memory Allocation Error." << endl; Exit (1); } For (int i = 0; i DELETE [] Templist; SIZE = CallbackList_increment; } CallbackList [lastpos] = EventRecord (Event, PCBSF); LastPOS ; } FILE: / / Delete Member Functions Registered on Specified Events Void Callback :: RemoveCallback (Char * Event, CallbackFunction PCBF, CALLBACK * PCBO) { IF ((Event == NULL)? 1: (Strlen (Event) == 0)) Return; EventRecord ER (Event, PCBO, PCBF); For (int i = 0; i IF (CallbackList [i] == ER) CallbackList [i] .flush (); } File: // Delete Static member functions or normal functions registered on specified events Void Callback :: RemoveCallback (Char * Event, CallbackStaticFunction PCBSF) { IF ((Event == NULL)? 1: (Strlen (Event) == 0)) Return; EventRecord Er (Event, PCBSF); For (int i = 0; i IF (CallbackList [i] == ER) CallbackList [i] .flush (); } File: // Delete all the callback functions registered on the specified event Void Callback :: RemoveCallback (Char * Event) { IF ((Event == NULL)? 1: (Strlen (Event) == 0)) Return; For (int i = 0; i IF (CallbackList [i] == Event) CallbackList [i] .flush (); } Void Callback :: CallCallback (Char * Event, CallData CallData) { IF ((Event == NULL)? 1: (Strlen (Event) == 0)) Return; Callback * PCBO; Callbackfunction PCBF; Callbackstaticfunction PCBSF; MoveFirst (); While (! endoflist ()) { File: // For the current event record and the specified event does not match, transfer to the next record to continue loop IF (! (CallbackList [CURPOS] == Event)) { MoveNext (); CONTINUE; } File: // find a matching record PCBO = CallbackList [CURPOS] .pointertocbo; File: // If the callback object pointer is empty in the event record, it will indicate that the static function pointer is saved. IF (PCBO == NULL) { PCBSF = CallbackList [CURPOS] .pointertocbsf; PCBSF (CallData); // Call the static callback function } Else file: // If the callback object pointer is non-empty, it will indicate that the member function pointer is saved. { PCBF = CallbackList [Curpos] .pointertocbf; (PCBO -> * PCBF) (CallData); // Call the member function of the callback object } MoveNext (); } }