Original article Address: http://www.cnblogs.com/zplutor/archive/2011/09/17/2179756.html
"Delegate mode C + + implementation"
I'm right. NET's delegation model is very impressive, using a delegate, you can quickly implement the observer pattern, eliminating the writing of a lot of repetitive code. Unfortunately, C + + does not provide such a model, in order to achieve similar purposes, you need to inherit a class and rewrite the virtual method, this practice requires writing a lot of code, inefficient (used MFC should be able to understand). However, in the face of strong C + +, nothing is impossible, there are many people have studied this issue, and implemented a variety of commissioned models, the most famous is fastdelegate, this model in the Member Function pointers and the Fastest Possible C + + Delegates "(Original address: http://www.codeproject.com/KB/cpp/FastDelegate.aspx). This model is characterized by "Fast", so it is inevitable to rely on the implementation of the compiler, although the final description of the model has been in most of the compiler passed the test, I still do not worry about it, if the compiler upgrade after the change of implementation mode, this model is not suitable for use. And I don't want to delve into the specific implementation of each compiler because of its limited level and lazy mentality. What I want is a model that complies with the C + + standard, regardless of whether it is "Fast" or not. After constant groping, finally wrote a commissioned model, the following share with you the implementation of the model of the principle. (Of course, if you think that Fastdelegate has satisfied the requirements and is not concerned that it relies on the compiler, you can ignore this article completely)
member function pointers
Before you begin, introduce member function pointers, which differ greatly from the way non-member function pointers are manipulated. There is a class like this:
Class a{public : void Func (int) { std::cout << ' I am in A ' << Std::endl; }
To get a pointer to the Func function, you must do this:
void (A::* pFunc) (int) = &A::Func;
::* is a special operator that indicates that Pfunc is a pointer to a member function . The address of the Get member function cannot be obtained through the class object , it must be obtained by the class name as above, and the Fetch address operator (&) is added.
So how do you call the function with a member function pointer? The member function has an implied this parameter, which represents the object to which the function is to manipulate, and now we get only the pointer to the function, and an object is missing as the This parameter. To achieve this, you need to create an object and then invoke the member function pointer through the object:
A; (A.*pfunc) (10); A *pa = &a; (pa->*pfunc) (11);
The first method is called through the object itself, and the second is called by an object pointer, and the effect is the same in both ways. . * and ->* are special operators that do not have to dwell on their strange appearance, as long as they know they are only used to invoke member function pointers.
Working with template classes
From the above introduction, we know that to invoke a member function , only the member function pointers are not enough, but also need a pointer to the object, so a class will be tied together. Because the type of the object is infinite, the class template must be used here:
Template <typename t>class Delegatehandler{public:delegatehandler (t *pt, void (t::* pFunc) (int)): M_pt (PT), m_ PFunc (pFunc) {}void Invoke (int value) {(M_pt->*m_pfunc) (value);} Private:t *m_pt;void (T::* m_pfunc) (int);};
You can use the template as follows:
A a;delegatehandler<a> dha (&a, &a::func);d ha. Invoke (3); B b;delegatehandler<b> DHB (&b, &b::method);//b::method's declaration is similar to A::func Dhb.invoke (4);
Here's a question: What if you want the target to be called a non-member function? The class template above cannot invoke non-member functions, but using template biasing can solve this problem:
Template<>class delegatehandler<void>{//void replaces the preceding type T, which indicates that the class template has no parameter Public:delegatehandler (void (*pFunc) ( int)): M_pfunc (pFunc) {}void Invoke (int value) {(*m_pfunc) (value);} Private:void (*m_pfunc) (int);};
The same approach is used:
void nonmemberfunc (int param) {std::cout << "I am in nonmemberfunc!" << Std::endl;} Delegatehandler<void> DHF (Nonmemberfunc);d HF. Invoke (5);
Using polymorphic
For a single-objective delegate, it might be enough to use the above code. But my purpose, of course, is more than that, and what I want is a multi-objective mandate. A multi-objective delegate is actually a container in which multiple objects can be stored (the object here refers to a delegate object, not a or b), and each object is called in turn when the delegate is invoked. The objects in the container should all be of the same type, so that they can be placed in a strongly typed container, and the delegate caller should not know what the specific invocation target is, so these objects should also hide specific details. Unfortunately, the class templates implemented in the previous step do not have these capabilities,delegatehandler<a> and delegatehandler<b> are different types and cannot be placed in the same container, and callers must know when they want to invoke them. What type is the target of the call .
The solution to this problem is to use polymorphism, so that all the delegate target classes inherit a common interface, and the caller only makes calls through this interface, so that you do not have to know the specific type of each target (the object here or the delegate). Here is the definition of the interface:
Class Idelegatehandler{public:virtual ~idelegatehandler () {}virtual void Invoke (int) = 0;};
Then let Delegatehandler inherit the interface:
Template<typename t>class delegatehandler:public idelegatehandler{public:delegatehandler (t *pT, void (t::* PFUNC) (int)): M_pt (PT), M_pfunc (pFunc) {}virtual void Invoke (int value) override {(M_pt->*m_pfunc) (value);} Private:t *m_pt;void (T::* m_pfunc) (int);}; Template<>class delegatehandler<void>: Public Idelegatehandler{public:delegatehandler (void (*pFunc) ( int)): M_pfunc (pFunc) {}virtual void Invoke (int value) override{(*m_pfunc) (value);} Private:void (*m_pfunc) (int);};
It is now possible to put various types of delegatehandler in the same container and invoke it in the same way:
A; B b;delegatehandler<a> dha (&a, &a::* Func);D elegatehandler<b> dhb (&b, &b::* Method);D Elegatehandler<void> DHF (Nonmemberfunc);std::vector<idelegatehandler*> Handlers;handlers.push_back ( &dha); Handlers.push_back (&DHB); Handlers.push_back (&DHF);//Auto equals Std::vector<idelegatehandler here *>::const_iteratorfor (Auto Itor = Handlers.cbegin (); Itor! = Handlers.cend (); ++itor) {(*itor)->invoke (7);}
Note that when compiling under Linux, if you compile with GCC or g++, you must add -std=c++ One, because auto , cbegin () , cend () is a new feature of c++11.
Design mode--delegate mode C + + implementation