Terms 38: Design the imitation function class as the value transfer
C and C do not allow you to truly pass the function as a parameter to other functions. Instead, you must pass the pointer to the function. For example, there is a standard library function QSort statement:
Void Qsort (void * base, size_t nmemb, size_t size,
INT (* CMPFCN) (Const void *, const void *);
Terms 46 explain why the Sort Algorithm is generally better than the QSort function, but it is not a problem here. The problem is the parameter CMPFCN declared by QSort. Once you have ignored all the asterists, you can clearly see the parameters transmitted as the CMPFCN, a pointer to the function, is from the call back (that is, value delivery) to Qsort. This is the general guidelines followed by the C and C standard libraries, that is, the function pointer is the value transfer.
STL function object is formed after the function pointer, so the habit in STL is the function object is also transmitted when the function is transmitted and the function returns from the function (that is, copy). The best evidence is the standard for_each declaration, this algorithm passes the value of acquisition and returns to function objects:
Template Class Function> Function // Note the value returns For_each (InputITerator First, InputITerator Last, Function f); // Note value transfer In fact, the situation of the value is not completely fighting, because the calling point of the for_each can explicitly specify the parameter type in the call point. For example, the following code allows for_each to pass and return its imitation function by reference: Class DOSMETHING: Public unary_function Void Operator () (int x) {...} ... } TypeDef Deque DEQUE ... DOSMETHING D; / / Establish a function object ... For_each DOSMETHING &> (DI.BEGIN (), // Type is DequeIntiter Di.end (), // and dosomething &; d); // This forces D to be referenced // Transfer and return But STL users cannot do such things, and if the function object is a reference delivery, some STL algorithms do not even compile. In the remainder of this Territor, I will continue to assume that the function object is always transmitted. In fact, this is true that it is always true. Because the function object is passed and returned, your task is to make sure your function object is good when it is transmitted (that is, copy). This suggests two things. First, your function object should be small. Otherwise, their copy will be very expensive. Second, your function object must be single (that is, non-polymorphism) - they can't use virtual functions. That is because the derived class objects can cause cutting problems with parameters of the value of the value into the base type: When copying, their derived part is deleted. (How to cut the problem affects another example of using STL See Terms 3.) Of course, efficiency is important, avoiding cutting problems, but not all the imitation functions are small, single. One of the reason why the function object is more than the true function is that the imitation function can contain all the status you need. Some function objects will naturally be very important, and keep such an imitation function is as easy as the STL algorithm and the function versions of the biography. The prohibited polymorphism function is unrealistic. C supports inheritance hierarchy and dynamic binding, which is useful when designing the function class and other things. Imitation functional class If the lack of inherits, like C lacks " ". It is indeed a way to make large and / or polymorphic function objects still allow them to spread STL in the way the value transfer function. This is what. With the data and / or polymorphism of you to put into your imitation function, move them to another class. Then give your function a pointer to this new class. For example, if you want to create a polymorphic imitation function class containing many data. Template Class BPFC: // BPFC = "Big Polymorphic Public // function Class Unary_function Private: Widget W; // There are a lot of data, INT X; // So use the value to pass ... // will affect efficiency PUBLIC: Virtual void Operator () (const t & var) const; // This is a virtual function, ... // So problems with cutting } Create a small-ortened class containing a pointer to implement the class, then put all the data and virtual functions to the implementation class: Template Class BPFCIMPL {// new implementation class Private: Widget W; // All data in BPFC before INT X; / / now here ... Virtual ~ bpfcimpl (); // Polymorphism // Vocabulary function Virtual Void Operator () (Const T & VAL) Const; Friend Class BPFC } Template Class bpfc: // small, single version of BPFC Public unary_function Private: BPFCIMPL PUBLIC: Void Operator () (const t & var) const // is now non-virtual; {// call BPFCIMPL PIMPL-> Operator () (VAL); } ... } BPFC :: Operator () Implementation illustration The BPFC all virtual functions are implemented: they call their true virtual functions in BPFCIMPL. The result is that the imitation function class (BPFC) is small, but can access a large state and behavior. I have ignored a lot of details here because I have been a widely known in the C circle. "Effective C " is available in Terms 34. This is called "Bridge mode" in "Design Mode" [6] of Gamma et al. SUTTER calls its "PIMPL IQ" in his "Exceptional C " [8]. From the perspective of STL, the most important thing to remember is to use this technique of imitation functional classes that must support reasonable ways. If you are the author of the BPFC above, you must ensure that its copy constructor makes a reasonable thing to point to the BPFCIMPL object. Perhaps the simplest reasonable thing is a reference count, using Shared_Ptr like Boost, you can understand it in terms 50. In fact, for the purpose of this Terms, the only thing you have to worry is the behavior of the BPFC copy constructor, because When it is passed or returned from a function, the function object is always passed, remember? That means two things. Let them be small, and let them log.