Although I do not use the Qt framework, I am very interested in the signal slot mechanism. Recently, I read csdn several articles on signal slots. From my own point of view, the records are as follows:
Implementation of signal slot mechanism with c + +
Personal understanding of the signal slot mechanism: a signal slot is a channel that establishes a connection between two c + + class objects. One object can be called a signal sender and the other object can be called a signal receiver. After the sender sends a signal through the signal slot, the receiver can execute functions to perform some operations. In other words, the application program can establish a logical relationship between two unrelated objects through the signal slot, which makes the program development concise and convenient.
Signal slot is essentially composed of classes defined by c + +, which is divided into two parts: slot class and signal class
Slot: it can be understood as a slot. There are two private members inside it, which store the class object to be executed and the method pointer in the object. It can be understood that the signal receiver is inserted into the slot. The other end of the slot is connected to the signal, which is realized by storing the slot pointer in the instance of the signal class. If multiple slots are inserted into the signal object, it means that a signal has established a connection with multiple recver s. When the signal comes, the event method can be executed in turn according to the insertion sequence of slots.
Signal class: there is a container inside, which stores the slot class pointer connected to the signal class instance, and provides an execution method. When the method is called, the method of recever stored in the slot pointed to by the stored slot class pointer is called inside the method.
To use the signal slot, the signal sender class needs to include an internal instance of the signal class and a method to call the execution method on the signal. This method is called signaling.
To sum up, any object class as a sender contains a signal member, sends a signal through func, and calls object The execution method on signal is implemented here by overloading (). Inside the execution method is a circular call to the slot pointer list saved in signal, and the slot instance pointed to by the slot pointer stores recver and recver Func, you can execute func through the exec method of slot, which realizes a complete process of trigger signal.
In order to realize the association of any sender and any receiver, the slot and signal classes do not know the specific types and parameter types of the object to be associated and the execution method, so generic programming should be used
The code and description are as follows (collated from csdn):
/// <summary> ///First implement the slot base class, which contains two virtual function objects, mainly providing interfaces for subsequent calls ///Subclasses are responsible for implementing exec methods /// </summary> ///< typeparam name = "tparam" > parameter type of the function to be executed in the recur < / typeparam > template <class TParam> class SlotBase { public: virtual void Exec(TParam param) = 0; virtual ~SlotBase() {}; }; /// <summary> ///The Slot subclass is responsible for implementing the exec method and calling the recver Func, and the Slot constructor is responsible for initializing two internal variables, which will require the associated recver and recver Func insertion Slot /// </summary> ///< typeparam name = "Trever" > specific type of recver class < / typeparam > /// <typeparam name="TParam">recver. Parameter type of func < / typeparam > template <class TRecver,class TParam> class Slot:public SlotBase<TParam> { public: Slot(TRecver* pObj, void (TRecver::* func)(TParam)) { m_pRecver = pObj; m_func = func; }; VOID Exec(TParam param) { (m_pRecver->*m_func)(param); }; private: TRecver* m_pRecver = NULL; void (TRecver::* m_func)(TParam); }; /// <summary> ///Signal class ///Private member m_pSlotSet, vector of storage slot pointer ///Overloaded (), when the parameter is called in parentheses, M is called in a loop_ The slot pointer stored in pslotset passes parameters to the exec method of the slot ///bind(): associate a slot with a signal class instance /// /// </summary> ///< typeparam name = "tparam" > parameter type of the method to be executed < / typeparam > ///< typeparam name = "Trever" > type of recver class < / typeparam > template<class TParam> class Signal { public: template<class TRecver> void Bind(TRecver* pObj, void (TRecver::* func)(TParam)) { m_pSlotSet.push_back(new Slot<TRecver,TParam>(pObj, func)); }; void operator()(TParam param) { for(int i=0;i<m_pSlotSet.size();i++) { m_pSlotSet[i]->Exec(param); } }; ~Signal() { for (int i = 0; i < m_pSlotSet.size(); i++) delete m_pSlotSet[i]; }; private: std::vector<SlotBase<TParam>*> m_pSlotSet; }; //Start simulation class RecverOne { public: void functionOne(int param) { std::cout << "This is a method execution in receiver 1:" << param << std::endl; }; }; class RecverTwo { public: void functionTwo(int param) { std::cout << "This is a method execution in receiver 2:" << param << std::endl; }; }; class SenderObj { public: //Signal when analog value changes void testSginal(int param) { valueChanged(param); }; public: Signal<int> valueChanged;//Defines a signal that is triggered when the value changes }; //To more easily associate the signal in the sender with the slot and the receiver, you can define a macro #define connect(sender,signal,recver,method) ((sender)->signal.Bind(recver,method)) int main() { //Start test //Define two recipients first RecverOne* R1 = new RecverOne; RecverTwo* R2 = new RecverTwo; //Define a sender SenderObj* sd = new SenderObj; //Insert the functions in R1 and R2 into the signal slot in sd connect(sd, valueChanged, R1, &RecverOne::functionOne); connect(sd, valueChanged, R2, &RecverTwo::functionTwo); //Send signal sd->valueChanged(5); std::cout << "Hello World!\n"; }