📄 ch03.htm
字号:
MsgLand : { Can't land if already on the ground. } if status = OnRamp then begin Response := Name + `: I''m already on the ground.';</PRE><P><B>Result := False;</B></P><P><PRE> end else Land; MsgReport : begin GetStatus(Response); Exit; end; end; { Standard response if all went well. } if Result then Response := Name + `: Roger.';end;function TAirplane.GetStatus(var StatusString : string) : Integer;begin StatusString := Format(`%s, Altitude: %d, Heading: %d, ` + `Speed: %d', [Name, Altitude, Heading, Speed]); Result := Status;end;function TAirplane.GetStatus : Integer;begin Result := Status;end;function TAirplane.GetSpeed : Integer;begin Result := Speed;end;function TAirplane.GetHeading : Integer;begin Result := Heading;end;function TAirplane.GetAltitude : Integer;begin Result := Altitude;end;function TAirplane.GetName : string;begin Result := Name;end;end.</PRE><P><B>ANALYSIS: </B>Look first at the class declaration in the interface section.Notice that the TAirplane class has one overloaded function called GetStatus. Whencalled with a string parameter, GetStatus will return a status string as well asthe status data member (the string parameter is a variable parameter). When calledwithout a parameter, it just returns Status. Note that the only way to access theprivate fields is via the public methods. For example, you can change the speed,altitude, and heading of an airplane only by sending it a message. To use an analogy,consider that an air traffic controller cannot physically change an aircraft's heading.The best he can do is send a message to the pilot and tell him to change to a newheading.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> This class would benefit greatly from properties. As I said earlier, I'm not ready to discuss properties in detail at this point in the book, so I'll have to admit that this class could be much better than it is and move on. <HR></BLOCKQUOTE><P>Now turn your attention to the definition of the TAirplane class in the interfacesection. The constructor performs some initialization chores. You have probably noticedthat the SendMessage function does most of the work. A case statement determineswhich message was sent and takes the appropriate action. Notice that the TakeOffand Land procedures cannot be called directly (they are protected) but rather arecalled through the SendMessage function. Again, as an air traffic controller, youcan't make an aircraft take off or land, you can only send it a message telling itwhat you want it to do.</P><P>There's something else here that I haven't discussed yet. Note the virtual keyword.This specifies that the function is a virtual method.</P><P><strong>New Term:</strong> A <I>virtual method</I> is a method that is automaticallycalled if a method of that name exists in the derived class.</P><P>I'll discuss virtual methods in the next section, but I wanted to point them outto you now.</P><P>The book's code contains a program called Airport, which enables you to play airtraffic controller. (You can find the book's code at the Web site http://www.mcp.com/info.Type in the book's ISBN: 0-672-31286-7.) The program first sets up an array of TAirplaneclasses and then creates three instances of the TAirplane class. You can send messagesto any airplane by selecting the airplane, setting up the parameters for the message,and then clicking the Execute button. Clicking the button results in a call to theselected airplane's SendMessage function. When you send a message, you get a responseback from the airplane, and that response is displayed in a memo component. Run theprogram and play with it to get a feel for how it works. Figure 3.1 shows the Airportprogram running.</P><P><H2><A NAME="Heading18"></A>Inheritance</H2><P>One of the most powerful features of classes in Object Pascal is that they canbe extended through inheritance.</P><P><strong>New Term:</strong> <I>Inheritance</I> means taking an existing class and addingfunctionality by deriving a new class from it.</P><P><PRE><strong>New Term:</strong> The class you start with is called the <I>base class</I> or <I>ancestor class</I>, and the new class you create is called the <I>derived class</I>.</PRE><P>To illustrate, let's go back to the TAirplane class. The civilian and militaryworlds are quite different, as you know. To represent a military aircraft, I canderive a class from TAirplane and add functionality to it:</P><P><PRE>TMilitaryPlane = class(TAirplane)private TheMission : TMission; constructor Create(AName : string; AType : Integer); function GetStatus(var StatusString : string) : Integer; override;protected procedure TakeOff(Dir : Integer); override; procedure Land; override; procedure Attack; virtual; procedure SetMission; virtual;end;</PRE><P>A TMilitaryPlane has everything a TAirplane has, plus a few more goodies. Notethe first line of the class declaration. The class name in parentheses after theclass keyword is used to tell the compiler that I am inheriting from another class.The class from which I am deriving this class is the base class and, in this case,is the TAirplane class.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> When you derive a class from another class, the new class gets all the functionality of the base class plus whatever new features you add. You can add fields and methods to the new class, but you cannot remove anything from what the base class offers. <HR></BLOCKQUOTE><P>You'll notice that in the private section there is a line that declares a variableof the TMission class. The TMission class is not shown here, but it could encapsulateeverything that deals with the mission of a military aircraft: the target, navigationwaypoints, ingress and egress altitudes and headings, and so on. This illustratesthe use of a field that is an instance of another class. In fact, you'll see thata lot when programming in Delphi.</P><P><H2><A NAME="Heading19"></A>Overriding Methods</H2><P>I want to take a moment here to discuss virtual methods. Note that the TakeOffprocedure is a virtual method in the TAirplane class (refer to Listing 3.1). Noticethat TakeOff is called by SendMessage in response to the MsgTakeOff message. If theTMilitaryPlane class did not provide its own TakeOff method, the base class's TakeOffmethod would be called. Because the TMilitaryPlane class <I>does</I> provide a TakeOffmethod, that method will be called rather than the method in the base class.</P><P><strong>New Term:</strong> Replacing a base class method in a derived class is called<I>overriding</I> the method.</P><P>In order for overriding to work, the method signature must exactly match thatof the method in the base class. In other words, the return type, method name, andparameter list must all be the same as the base class method. In addition, the methodin the derived class must be declared with the override keyword.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> Object Pascal also has <I>dynamic methods</I>. Dynamic methods can be treated the same as virtual methods as far as most programmers are concerned. The difference is in the way the method pointers are stored in the class's virtual method table (VMT). It's not important for you to understand the difference right now, but I wanted you to know about dynamic methods in case you encounter them looking through any of the Delphi examples or VCL source code. For the most part, you can treat dynamic methods in your programs just as you would treat virtual methods. <HR></BLOCKQUOTE><P>You can override a method with the intention of replacing the base class method,or you can override a method to enhance the base class method. Consider the TakeOffmethod, for example. If you want to completely replace what the TakeOff method ofTAirplane does, you would override it and supply whatever code you want:</P><P><PRE>procedure TMilitaryPlane.TakeOff(Dir : Integer);begin { New code here. } end;</PRE><PRE>But if you want your method to take the functionality of the base class and add to it, you would first call the base class method and then add new code. Calling the base class method is done with the inherited keyword--for example,</PRE><PRE>procedure TMilitaryPlane.TakeOff(Dir : Integer);begin { First call the base class TakeOff method. } inherited TakeOff(Dir); { New code here. } end;</PRE><P>By calling the base class method, you get the original behavior of the methodas written in the base class. You can then add code before or after the base classcall to enhance the base class method. Note that the TakeOff method is declared inthe protected section of the TAirplane class. If it were in the private section,this would not work because even a derived class cannot access the private membersof its ancestor class. By making the TakeOff method protected, it is hidden fromthe outside world but still accessible to derived classes.</P><BLOCKQUOTE> <P><HR><STRONG>NOTE:</STRONG> There is an exception to the rule of protected versus private access. If a derived class is declared in the same unit as the base class, the private fields and methods of the base class are available to the derived class. If the derived class is declared in a separate unit, only protected fields and methods of the base class are available to the derived class. <HR></BLOCKQUOTE><P>When you derive a class from another class, you must be sure to call the baseclass's constructor so that all ancestor classes are properly initialized. Callingthe base class constructor is also done with the inherited keyword. Look again atthe constructor for the TAirplane class:</P><P><PRE>constructor TAirplane.Create(AName : string; AKind : Integer);begin inherited Create; Name := AName; Kind := AKind; Status := OnRamp; case Kind of Airliner : Ceiling := 35000; Commuter : Ceiling := 20000; PrivateCraft : Ceiling := 8000; end;</PRE><P><B>end;</B></P><P>Notice that the base class Create constructor is called to ensure that the classis properly created. "Hey, wait a minute!" I can hear some of you saying."The TAirplane class doesn't have a base class!" Actually, it does. Ifno base class is specified when the class is declared, the base class is automaticallyTObject. Be sure to call the base class constructor in your class constructor. Figure3.2 illustrates the concept of inheritance.</P><P><A HREF="javascript:popUp('28670302.gif')"><B>FIGURE 3.2.</B></A><B> </B><I>Anexample of inheritance.</I></P><P>You can see in Figure 3.2 that the class called F16 is descended from the classcalled MilitaryFighter. Ultimately, F16 is derived from TAirplane because TAirplaneis the base class for all of the airplane classes.</P><P><H3><A NAME="Heading20"></A>Class Keywords: is and as</H3><P>Object Pascal has two operators that pertain specifically to classes. The is operatoris used to determine whether a class is of a specific type. Let's go back to theexample of the TAirplane and TMilitaryPlane classes. Let's say you have an instanceof a class called Plane. The class might be an instance of the TAirplane class, itmight be an instance of the TMilitaryPlane class, or it might be an instance of adifferent class altogether. You can use the is operator to find out. For example:</P><P><PRE>if Plane is TMilitaryPlane then Attack;</PRE><PRE>The is operator returns a Boolean value. If the variable is of the requested type, is returns True. If the variable is not of the requested type, is returns False. The is operator will also return True if the requested class type is an ancestor of the variable. For example, because TMilitaryPlane is derived from TAirplane, the following will be True:</PRE><PRE>if Plane is TAirplane then DoSomething;</PRE><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> Because all classes are derived from TObject, the following will always be True:</P> <PRE>if AnyClass is TObject then</PRE> <PRE> DoSomething; </PRE></BLOCKQUOTE><PRE></PRE><BLOCKQUOTE> <P>The is operator is not used as much as the as operator. The as operator is used to cast a pointer to a specific class type. It looks like this:</P> <PRE>with Plane as TMilitaryPlane do</PRE></BLOCKQUOTE><PRE></PRE><BLOCKQUOTE> <PRE>Attack;</PRE> <P><HR></P></BLOCKQUOTE><P>The as operator is usually used in conjunction with the with operato
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -