We all know that objects are the encapsulation bodies of data and methods. In C ++, they are data members and member functions. The program designer changes the object state by executing various methods of the object (that is, changing the attribute data of the object ). In this way, some "events" occur to this object ". When an object has an event, it usually needs to send a "message" to other related objects and request them for some processing. At this time, the object that occurs and requests to other objects is called the "event object", and the object that handles the event is called the "Callback object ". A callback object is called a callback function to process events ". In C ++, this process is equivalent to calling some member functions of the callback object when an event occurs. Generally, the callback object transmits the object pointer to the event object. However, this method is not universal. In order to reduce the workload of program design, this paper proposes a system method for establishing message connections between objects. The idea is to abstract the process "event occurrence> request processing> Execution Processing" into a "Callback" class. With inheritance, you can easily obtain the mechanism for establishing message connections between objects.
I. Data Structure and member functions of the callback class
The callback class proposed in this article supports three types of callback functions. They are member functions in the callback object, static member functions and common C functions in the callback class. The callback class contains a callback function table callbacklist. It is used to record the event name and point to the callback function and the pointer to the callback object. Each node in the table is an event record eventrecord. Each event record contains three domains: The event name pointer eventname, the pointer to the callback object pointertocbo, And the pointer to the callback function pointertocbsf or pointertocbsf (wherein, pointertocvr points to the member function of the callback object, pointertocbsf points to the static member function or common function of the callback class. ). The callback mechanism provided by the callback class is as follows: register the callback function in the callback object on the event object; when an event occurs, the event object retrieves and executes the callback function in its callback table. So that the message connection between the two can be established. (For the specific implementation of this class, see the program list attached to the article) callback object
Event object
Event name |
Callback object pointer |
Callback function pointer |
"Event" |
Pointercbo |
Pointertocbsf or pointertocbsf |
Addcallback: registers the event name and the pointer to the callback function and the callback object.
Callcallback: In the callback table, retrieve the callback functions registered on the specified event and call them.
Call the callcallback function when an event occurs.
Member functions that process event
Callbacklist inherited from the callback class, which includes the member functions addcallback and callback.
When the callback function is a static member function or a common C function, pointertocbo is null.
The event name is the retrieval keyword in the callback table callbacklis.
Other member functions in the callback object
The member function addcallback of the callback class is used to register the callback function to the callback table of the event object. It has two overloaded versions.
Void callback: addcallback (char * event, callbackfunction CBF, callback * P ); Void callback: addcallback (char * event, callbackstaticfunction cbsf ); |
The first addcallback is used to register the member functions of a callback object to the callback table of the event object. The second addcallback is used to register static member functions of a callback class to the callback table of the event object. In the preceding parameter table, event is the pointer to the event name string, p is the pointer to the callback object, and cbsf is the pointer to the member function and static member function (or common function) respectively) pointer. When a callback function comes from a callback object someobject, the passed member function pointer should adopt the following format: (callbackfunction) & someobject: memberfunctionname; when passing a static member function pointer of the someobject class, the format should be: (callbackstaticfunction) & someobject: functionname; when passing a common function pointer in a program, you only need to pass the function name.
The callback class member function void callback: callcallback (char * ename, calldata = NULL) is used to call all the callback functions registered on the event ename. Among them, calldata is the Data Pointer (calldata is actually void *, see the program list ). The event object can pass useful data to the callback object. This member function is usually called in the member function of the event object, because only the member function of the event object can change the internal data of the object, so that some events occur.
The member function removecallback is used to delete the callback function registered on the event object. The three overloaded versions are as follows:
Void callback: removecallback (char * event, callbackfunction CBF, callback * P ); Void callback: removecallback (char * event, callbackstaticfunction cbsf ); Void callback: removecallback (char * event ); |
Among them, parameters such as event, cbsf, and P are the same as those in the member function addcallback. The first removecallback is used to delete a member function registered with a callback object on the event. The second removecallback is used to delete a common function registered on the event or a static member function of a callback class. The third removecallback is used to delete all callback functions registered on the event.
Ii. usage of the callback class
To use the callback class, follow these steps:
1. Determine which objects in the program have a relationship and establish a message connection. Determine which object is the event object and which is the callback object in the connection relationship of each specific message.
2. Both the event object class and the callback object class must inherit from the callback class to obtain callback support.
3. Register callback data for the event object. Including the event name, callback function name, and pointer to the callback object.
4. When an event you are interested in occurs, call the callcallback function in the member function that triggers the event in the event object class.
The following is a specific example. You will have a better understanding of the usage of the callback class.
// Test program file: Test. cpp # Include "Callback. H" // Speaker class Class Speaker: Public callback { PRIVATE: Int volume; Public: Speaker (int v): volume (v ){} Void increasevolume (INT v) // adds the volume member function. { Volume + = V; If (volume> 20) {// "volume greater than 20" event occurred // Call the callback function registered on two events Callcallback ("volume changed "); Callcallback ("volume greater than 20", & volume ); } } Void decreasevolume (INT v) // function for reducing the volume of a member { Volume-= V; If (volume <5) {// "volume less than 5" event occurred // Call the callback function registered on two events Callcallback ("volume changed "); Callcallback ("volume less than 5", & volume ); } }// "Ears" Type Class ear: Public callback { Public: Static void response (calldata) // response to "volume change" { Cout <"the volume has changed." <Endl; } Void highvoiceresponse (calldata) // high-pitched response { Cout <"hello! Too noisy! The current volume is: "<* (int *) calldata) <Endl; } Void lowvoiceresponse (calldata) // response to the bass { Cout <"Ah! I cannot hear it. The current volume is: "<* (int *) calldata) <Endl; } }; Void main (void) { Speaker S (10); // The current volume is 10 Ear E; // Register the callback function for event object s S. addcallback ("volume greater than 20", (callbackfunction) & ear: highvoiceresponse, & E ); S. addcallback ("volume less than 5", (callbackfunction) & ear: lowvoiceresponse, & E ); S. addcallback ("volume changed", (callbackstaticfunction) & ear: Response ); S. increasevolume (12); // increase the volume by 12. The current volume is 22 S. decreasevolume (20); // reduce the volume by 20. Now the volume is 2 } |
Running result:
The volume has changed.
Hello! Too noisy! The current volume is 22.
The volume has changed.
Ah! I cannot hear it. The current volume is: 2
In the preceding example, the speaker object S is the event object, and the ear Object E is the callback object .. Three events are registered on S: "volume changed", "volume greater than 20", and "volume less than 5 ". The callback functions are: ear: Response, ear: highvoiceresponse, and ear: lowvoiceresponse. When the speaker s changes the volume through its member functions increasevolume and decreasevolume, the callback Object E automatically responds. It can be seen that using the callback class makes it easy and elegant to establish a message connection between objects.
Appendix: program list (this program is compiled on ms vc ++ 5.0 and TC ++ 3.0)
// Class structure of the callback class: callback. h # Ifndef _ callback_h # DEFINE _ callback_h # Include <stdlib. h> # Include <string. h> # Include <iostream. h> # Define callbacklist_init_size 10 # Define callbacklist_increment 5 Class callback; Typedef void * calldata; // callback Data Pointer Type Definition Typedef void (callback: * callbackfunction) (calldata); // pointer to the callback member function Typedef void (* callbackstaticfunction) (calldata); // pointer type definition pointing to a static member function or a common function Class eventrecord { PRIVATE: Char * eventname; // callback event name Callback * pointertocbo; // pointer to the callback object // Pointer to the member function and the shared body pointing to the static member function (or common function) pointer Union { Callbackfunction pointertocvr; Callbackstaticfunction pointertocbsf; }; Public: Eventrecord (void); // default constructor of the event record class // Construct event records containing member functions Eventrecord (char * ename, callback * pcbo, callbackfunction pcbf ); // Construct event records that contain static member functions or common functions Eventrecord (char * ename, callbackstaticfunction extends SF ); ~ Eventrecord (void); // destructor event record Void operator = (const eventrecord & Er); // overload value assignment operator // Determine whether the event name recorded by the current event is ename Int operator = (char * ename) const; // Determine whether the current event record is equal to the specified event record Int operator = (const eventrecord & Er) const; Void flush (void); // clears the current event record Int isempty (void) const; // determines whether the event record is empty (that is, whether the event name is empty) Friend class callback; // enables the callback class to access private members of eventrecord; }; Class callback { PRIVATE: Eventrecord * callbacklist; // callback event table Int curpos; // the location of the current event record Int lastpos; // The Last idle position in the callback table Int size; // the size of the callback table. Void movefirst (void) {curpos = 0;} // set the current record to the first record Void movenext (void) // set the next record to the current record { If (curpos = lastpos) return; Curpos ++; } // Determine whether the callback table has been traversed Int endoflist (void) const {return curpos = lastpos ;} Public: Callback (void); // Constructor Callback (const callback & CB); // copy the constructor ~ Callback (void); // destructor Void operator = (const callback & CB); // overload value assignment operator // Call back the member functions and static member functions (or common functions) of the object) // Callback function registered as an event object Void addcallback (char * event, callbackfunction CBF, callback * P ); Void addcallback (char * event, callbackstaticfunction cbsf ); // 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 records of an event // Execute all the callback functions registered on an event Void callcallback (char * event, calldata = NULL ); }; # Endif // Implementation of the callback class: callback. cpp # Include "Callback. H" // Implement the eventrecord class Eventrecord: eventrecord (void) { Eventname = NULL; Pointertocbo = NULL; // Because sizeof (callbackfunction)> sizeof (callbackstaticfunction) Pointertocbn = NULL; } Eventrecord: eventrecord (char * ename, callback * pcbo, callbackfunction pcbf) : Pointertocbo (pcbo), pointertocvr (pcbf) { Eventname = strdup (ename ); } Eventrecord: eventrecord (char * ename, callbackstaticfunction extends SF) : Pointertocbo (null), pointertocbsf (sort SF) { Eventname = strdup (ename ); } Eventrecord ::~ Eventrecord (void) { If (eventname) delete eventname; } Void eventrecord: Operator = (const eventrecord & Er) { If (ER. eventname) Eventname = strdup (ER. eventname ); Else Eventname = NULL; Pointertocbo = ER. pointertocbo; Pointertocbr = ER. pointertocbr; } 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)/* the location of ER and eventname cannot be changed */ & (Pointertocbo = ER. pointertocbo) & (Pointertocbo? (Pointertocbr = ER. pointertocbr ): (Pointertocbsf = ER. pointertocbsf )); } Void eventrecord: flush (void) { If (eventname ){ Delete eventname; Eventname = NULL; } Pointertocbo = NULL;Pointertocbn = NULL; } Int eventrecord: isempty (void) const { If (eventname = NULL) Return 1; Else Return 0; } // Callback class implementation Callback: callback (void) { // Allocate memory space for the callback table based on the initial size Callbacklist = new eventrecord [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 ); } // Copy all event records one by one For (INT I = 0; I <size; I ++) callbacklist [I] = CB. callbacklist [I]; } Void callback: Operator = (const callback & CB) { Curpos = CB. curpos; Lastpos = CB. lastpos; Size = CB. size; Delete [] callbacklist; // Delete the old callback table Callbacklist = new eventrecord [size]; // re-allocate memory space If (! Callbacklist ){ Cerr <"Callback: Memory Allocation Error." <Endl; Exit (1 ); } // Copy all event records one by one For (INT I = 0; I <size; I ++) callbacklist [I] = CB. callbacklist [I]; } Callback ::~ Callback (void) { Delete [] callbacklist; } Void callback: addcallback (char * event, callbackfunction pcbf, callback * pcbo) { // Exit if the event name is empty If (event = NULL )? 1 :( strlen (event) = 0) return; // Find the first idle location generated by deleting the event record, and fill in the new event record For (INT start = 0; Start <lastpos; Start ++) If (callbacklist [start]. isempty ()){ Callbacklist [start] = eventrecord (event, pcbo, pcbf ); Break; } If (start <lastpos) return; // there is indeed a free location // There is no idle position, and a new record is appended to the callback table If (lastpos = size) // The callback table is full and needs to be stretched" { Eventrecord * templist = callbacklist; // save the old callback table pointer // Call back the table with a certain step size. Callbacklist = new eventrecord [size + callbacklist_increment]; If (! Callbacklist ){ Cerr <"Callback: Memory Allocation Error." <Endl; Exit (1 ); } // Copy the records in the old callback table For (INT I = 0; I <size; I ++) callbacklist [I] = templist [I]; Delete [] templist; // Delete the old callback table Size + = callbacklist_increment; // write down the size of the new callback table } // 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 extends SF) { If (event = NULL )? 1 :( strlen (event) = 0) return; For (INT start = 0; Start <lastpos; Start ++) If (callbacklist [start]. isempty ()){ Callbacklist [start] = eventrecord (event, callback SF ); Break; } If (start <lastpos) return; // a hole is found If (lastpos = size) // 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 <size; I ++) callbacklist [I] = templist [I]; Delete [] templist; Size + = callbacklist_increment; } Callbacklist [lastpos] = eventrecord (event, callback SF ); Lastpos ++; } // Delete the member functions registered on the specified event 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 <lastpos; I ++) If (callbacklist [I] = ER) callbacklist [I]. Flush (); } // Delete static member functions or common functions registered on the specified event Void callback: removecallback (char * event, callbackstaticfunction extends SF) { If (event = NULL )? 1 :( strlen (event) = 0) return; Eventrecord Er (event, notify SF ); For (INT I = 0; I <lastpos; I ++) If (callbacklist [I] = ER) callbacklist [I]. Flush (); } // Delete All 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 <lastpos; I ++) If (callbacklist [I] = event) callbacklist [I]. Flush (); } Void callback: callcallback (char * event, calldata) { If (event = NULL )? 1 :( strlen (event) = 0) return; Callback * pcbo; Callbackfunction pcbf; Callbackstaticfunction extends SF; Movefirst (); While (! Endoflist ()) { // If the current event record does not match the specified event, transfer it to the next record to continue the loop. If (! (Callbacklist [curpos] = event )) { Movenext (); Continue; } // If a matching record is found Pcbo = callbacklist [curpos]. pointertocbo; // If the callback object pointer in the event record is null, the record stores the static function pointer. If (pcbo = NULL ){ Required Sf = callbacklist [curpos]. pointertocbsf; Pcbsf (calldata); // call this static callback function } Else // If the callback object pointer in the event record is not null, it indicates that the record stores the member function pointer. { Pcbf = callbacklist [curpos]. pointertocbr; (Pcbo-> * pcbf) (calldata); // call the member function of the callback object } Movenext (); } } |