Dialogue with prawns: Recognizing the design mode - Template Method / Visitor [Translator Press] This article is compiled according to the published in CUJ EXPERT Forum. C / C User's Journal is currently the best magazine, which is currently the best C / C language, especially after C Report is closed, Cuj's status is more prominent. CUJ EXPERT Forum is the online technology column hosted by CUJ, which brings together the technical and essays of top experts in the C community since October 2000, and freely public release, exciting, is a non-missed information of each C / C learner. The Conversation Series hosted by Jim Hyslop and Herb Sutter is a must-have bise column, which is a must-have quality column in the form of a humorous dialogue, which is widely praised in the C community. The translator specially selection two articles in two design patterns, introduces you to everyone. The classic works in design patterns are GOF's Design Patterns. But the book has a shortcoming, not understanding. From the style, the book is said to be a tutorial model for the learner, but it is better to say that the academic report will be seen from the academic people, and rigorous and more vivid. This includes the author of the book and the masters like Bjarne Stroustrup never say. In fact, Design Pattern is not necessarily unknown. Through vivid examples, a medium-level C learner can fully master basic usage, use it in its own programming practice to get immediate effect. These two articles are very good examples. This paper has made many deletions and modifications in the premise of ensuring technical integrity, so that the article is more compact. -------------------------------------------------- -------- Character introduction: I - a C programmer pursuing upward, still in the trial period, smart but experience. Wendy --- The technology of the company is sitting in the compartment next to me, C prawns, the most great thing is that she is a woman! She is good, it is a bit thin, I really worship her for her. -------------------------------------------------- -------- I. Virtually Yours - Template Method Mode I am studying a class written by Wendy. That is a abstract base class she written for this project, and my job is to give a concrete class from the middle school. The public part of this class is like this: Class Mountie {public: void read (std :: istream &); void write (std :: ostream &) const; virtual ~ mountie (); normal, Virtual Destructor indicates this class intended Inherited. Then look at its protected section: protected: virtual void do_read (std :: istream &); virtual void do_write (std :: ostream &) const; just a while, I have broken Wendy's trick: she is using Template Method mode. Public member functions Read and Write are non-virtual, they are definitely calling the protected section DO_READ / DO_WRITE virtual member function to complete the actual work.
Ah, I am just floating for my own progress! Ha, Wendy, this time you can't help me, what is the trick? Despite relying on the horse ... Suddenly, the smile is solidified on my face, because I saw its Private section: Private: Virtual st: string classid () const = 0; what is this? A private pure sequence function, can you work? I stood up, "Wendy, your mountie class doesn't seem to work yeah, it has a private virtual function." "You tried?" She didn't lift it. "Well, it is okay, but think about it. How can my derive class Override your private function?" I muttered. "Hey, you are very confirmed!" Wendy's voice is very soft, "How do you always do this? It's okay, these months follow me, you haven't learned something? Small vegetables." Okay ... "Small Rookie, you all have forgotten, the access control level is not a virtual basis with a function. Judging a function is the last step of dynamic binding or static binding is the final step of the function call parsing. Have read Standard 3.4 and 5.2.2. "I am completely under the wind and have to take interference tactics. "Well, even if you say it, I still don't understand. Why do you set it up to private?" "I and ask you, if you don't want to make a member function in a class, how should you handle? "" Of course, set it to private, "I replied. "So you go to see my Mountie class implementation, especially the implementation of the Write () function." I can't escape the whisper of Wendy, I turned to search on my screen, very fast, I found : Void mountie :: Write (std :: ostream & dudley) const {dudley << ClassID () << std :: end1; do_write (dudley);} Hey, recent cartoon card is really seen too much, actually Low-level mistakes. Still always admitted: "Well, I understand .classID () is a detail of implementation, used to save the object, the type of iconic class, the derived class must overwrite it, so it must be pure. But since it is To achieve details, it should be set to private. "" This is almost, the small rookie. "The prawn nodded." Now give me the do_read () and do_write () is protected? "This problem is not difficult?" I organized a try to answer: "Because the derived class object needs to call the implementation of these two functions to read and write the base class object." "Very good," prawn is almost satisfied, "But you explain again Explain why I don't set them as public? "I feel much now:" Because it is necessary to do in a specific way, you must write the type information, then use the object. Information is written, when reading, the module responsible for generating an object first can know what type of object to be read, and then read object information from the stream. "" Smart, my little rookie! "Wendy pauses," Like learning foreign speaking, learning C is not only mastering grammar, but also must master a large number of customary methods.
"Yeah, I am planning to read Coplien's book ..." [Translator Note: James Coplien 1992 classic book Advanced C Programming style and idioms] prawn waved her hand, "calm," The little rookie, I don't mean the book of the prophet Coplien, I refer to the inertial method behind a certain structure. For example, a class has Virtual Destructor, which is equivalent to telling you: 'Hey, I am a polymorphic base class, to inherit me! 'And if a class of Destructor is not a virtual, it is equivalent to saying:' I can't be used as a polymorphic class, watching it on the old days, don't inherit me. '"" The same, the Virtual function's access control level also has an implicit meaning. A protected virtual function tells you: 'The derived class you wrote, oh, but it is necessary to call my implementation. 'And a private virtual function is saying:' Deleted class can be overwritten, or you can not cover me, follow you. But you can't call my implementation. '"I nodded, tell her what I understood, then ask:" So what does Public Virtual Function? "Don't use the public Virtual function as much as possible. She wrote a pen and wrote the following code: Class HardtoExtend {public: Virtual void f ();}; void hardtoExtend :: f () {// perform a specific action} "Suppose you publish this class. When writing the second edition, the demand changes, you must use Template Method. But this is impossible, do you know why? "Hey, this ... I don't know." "" Both possible ways. First, transfer F () implementation code into a new function, then set f () itself to non-virtual: class hardtoExtend {// Possibly protected virtual void do_f (); public: void f () }; void hardtoExtend :: f () {// pre-processing do_f (); // post-processing} void hardtoExtend :: do_f () {// perform a specific anction} However, your original derived class is If you try to override functions f () instead of do_f (), you must change all derived class implementations, as long as you miss a class, your class level will be infected with the 'schizophrenia of MEYERS'. "[Translator Note: See Scott Meyers, Effective C , Item 37, absolutely don't redefine inherited non-virtual functions]" Another way is to move f () to the Private area, introduce a new Non-Virtual Function: "Class HardtoExtend {// POSSIBLY PROTECTED VIRTUAL VOID F (); public: void call_f ();};" This will result in countless a headache. First, all customers are trying to call f () instead of call_f (), and now their code cannot be compiled. What is even more, most of the derived classes returns F () in the public area, so that users who use derived classes can access the details you want to protect.
"" Treatment of virtual functions, like a data member, set them to Private until it is designed to use a more relaxed access control to adjust. You must know that it is easy by Private into public, it is difficult to get private by PUBLIC! "[Translator Note: The idea of this article has certain disruptive, because we are too easy to set public virtual function in the base class, and even specifically for this practice even specifically for this practice, now actually said this Not good! It is not acceptable for a while. But carefully understand the author's meaning, he is not generally opposing public Virtual Function, just gives the above principles in the background of Template Method. Although this principle is also worth considering in general design However, the main application field is still in the Template Method mode. Of course, Template Method is a very useful and common mode, so it has also determined the principle of this article has a wide range of significance.] --------- -------------------------------------------------- ----- ii. Visitor mode I am worried for a design problem. The trial period is over, I hope that I will solve this problem to prove my progress. Everyone remembers her first job, also I should know how important it is to do this time! I have seen other new employees, I have been fried squid, because they don't know how to deal with the prawns ..., don't misunderstand I don't mean she is not good. She is the best programmer I have ever seen, but I am a bit thin .... Now I worship her as a teacher, I don't do anything, because I hope that she can reach her height. I want to add a new virtual function in a class hierarch, but this class level is maintained by another part of people, others can't touch: Class Personnel {public: Virtual void pay (/ * ... * /) = 0; Virtual Void Promote (/ *...*/) = 0; Virtual Void Accept (Personnelv &) = 0; // ... Other functions ...}; Class Offer: Public Personnel {/ * Override Virtuals * /}; Class Captain: Public Offer {/ * Override Virtuals * /}; Class First: Public Offer {/ * Override Virtuals * /}; I want a function, if the object is the captain (CAPT AIN) Do this, if it is a big pair (first offic). Virtual Function is a solution, declare it in Personnel or Office, and override it in Captain and First. Worse, I can't add such a virtual function.
I know that I can give a solution with RTTI: void f (officer & o) {if (Dynamic_cast