Three multi-state - good use of Virtual
Author: Nicrosoft (nicrosoft@sunistudio.com) - 2002.4.30
Source: East Day Software Development Network (SSDN) http://www.ssdn.net
Polymorphism is a thing that can bring flexibility to the program. Programmers who have seen "design patterns" should know that quite a number of patterns (almost all) are relying on polymorphisms, with this to provide scalable and reusability. In the article "Talk to Polymorphism - Top Mapping and VMT / DMT", the polymorphism is referred to as virtual function / virtual method (ie dynamic binding), and also introduces virtual function / virtual method ( Implementation method of Virtual. So this article talks about how to use Virtual, make good use of Virtual to get the flexibility to us. The example is the best textbook, so this article is assumed to write a need to write an instance. However, I don't want to give all the source code, so some of the code implemented in this article will be roughly brought. In addition, all the code this article is written in Object Pascal language, and the environment is Delphi. In addition, since the word "method" has become the term Object Pascal, the following is called "method". Maybe C programmer will not adapt to such a name (huh, I am not adaptable), forgive me. Suppose we have to write an editor in a plain text, which is notepad (huh, don't be an example of the old set, the notebook is a very good textbook in considerable aspect), and the editor control us will generally use TMEMO or TRICHEDIT, But their functions are not very powerful, maybe we have no current, but later find a better third-party text editing control (for example, support grammar coloring). Therefore, we must leave a convenient door for future improvements, otherwise it is too stupid to rewrite all procedures. Interface layer (menu response, status display, etc.) The code for the control of the text editor control is similar to all editors, which should be reused. Then you must isolate the code of the interface layer to the control code of the editor control. How to isolate? We can specify a public interface (abstraction class) for all editor controls, and the interface layer only looks at this interface. Use only the features provided by the interface, then we do not have to change the interface of the interface when we replace any editor control. . First, the basic operation of the abstract editor, such as: LOAD, Save (saved to file), copy (copy to clipboard), etc., these operations use these operations as the public method. Second, consider what these operations will involve specific related controls. For these operations, you have two options: 1. If you rely on the control itself, you can choose to define it as a virtual method or abstract virtual method (ie C . The pure deficiency function); 2, if there is only some code dependent control itself, this part of the operation abstract into a protected abstraction method, and writes the same partial code in the base class, and by the base class The abstract virtual method of calling protected is called.
If not yet fully understood, see Code: TEditor = class // abstract base class private m_FileName: String; protected function DoLoad (FileName: String): Boolean; virtual; abstract; public function Load (FileName: String): Boolean; function Save (): Boolean; Function Saveas (FileName: String): Boolean; Virtual; Abstract; // ... Other needs, Date End; Ok, let's take a detailed note why TEDITOR is like this. It has a private member to save the file name corresponding to the editor. Then look at the public part, it provides at least three operations: LOAD - read the text to the editor from a file; save - save the text to the file, the file is saved by M_FileName; Saveas - in specified A file name saves text. In three operations, saveas is an abstract virtual method because its actual action is related to each editing control, and the base class itself does not know how to save the file.
Save and LOAD are non-virtual methods, where Save's tasks are simple, that is, save text with the file name saved by m_filename, which can be called abstract saveas, just pass the file name to save. The base class can determine how to complete SAVE (because it guarantees that the derived class implements Saves, it is a non-virtual method.
And what about LOAD? The step of the LOAD operation is: 1. Read the text from the file to the editor control; 2. Set the value of m_filename to the name of the file read. The first step is related to the specific editor control, which should be derived from derived classes, and the second step is not implemented because the derived class can not see the private M_FileName member. But even if M -FileName is moved to the Protected section, it is not a good way to access it, because of this, when implementing each derived class, remember to set the value of M_FileName, which not only causes code repeat ( Every derived class must do this), and this should not be the obligation of derived classes. Because m_filename should be internal implementation of the base class, it is not visible. Therefore, the second step should be completed by the base class. How to achieve this goal?
We can notice that there is a DOLOAD method in the Protected section, which is used to complete the first step - each editor control to read the text into the editor. Then, the DOLOAD is selected from the appropriate timing call from the LOAD method. The implementation of the base class is as follows:
function TEditor.Load (FileName: String): Boolean; begin Result: = DoLoad (FileName); if Result then m_FileName: = FileName; end; function TEditor.Save (): Boolean; begin SaveAs (m_FileName); // call the abstract the SaveAs end; Next, we use TMemo to implement an editor class: TMemoEditor = class (TEditor) private m_Editor: TMemo; protected function doLoad (FileName: String): Boolean; override; public constructor Create (); destrcutor Destroy () Override; Function Saves (FileName: String): Boolean; Override; // ... Other needs END; in this derived class, there is a private member, an instance of TMEMO controls. Then override the two abstract virtual methods of the base class: Doload and Save. It is achieved as follows: function tmemoEditor.create (); begin // Create a TMEMO instance m_editor: = tmemo.create (nil); // then complete the operation of the TMEMO instance is displayed on the interface, omitting the end; function tmemoEditor.Destroy (); Begin // Other cleanup work m_editor: = nil; end; function tmemoEditor.doload (filename: string): boolean; begin result: = false; try m_editor.loadFromFile (FileName); Except End Result: = true; end; function tmemoEditor.saveas (filename: string): boolean; begin result: = false; try m_editor.savetofile (filename); except end; result: = true; END; very good, this implementation It has been possible to make a part to operate normally. If you find a better editor control in the future, you only need to derive from TEDITOR, and then implement a TXXXEDITOR class, and the other part of the code is not used as any change. Moreover, the code in the TXXXEDITOR class, only related to the specific control itself (such as reading, saving file), and public logic has also been implemented in the TEDITOR class.
Virtual's use, based on the author's personal understanding and experience: Method - Virtual; Abstract; (ie the pure virtual function of C ). 2. If the base class can provide a default implementation for a method, the derived class may rewrite this implementation, then declare the method as the virtual method - Virtual; and implement the default algorithm. 3. If the base class is capable of providing some of the implementation of a method, the derived class must provide another part of the implementation, declare the method as a non-virtual method, and provide a virtual method for its support in the base class. Or abstract virtual methods to allow for calls from the base class itself and the derived class. It is like Load and Doload in the above example. Good use of Virtual, make good use, your code will be more flexible!