📄 ch03.htm
字号:
<HR></BLOCKQUOTE><H3><A NAME="Heading6"></A>Local Versus Dynamic Memory Usage</H3><P>Yesterday when you read about records, I showed you some examples. All of thoseexamples used local allocation of objects. That is, the memory required for the recordvariable was obtained from the program's stack.</P><P><I><strong>New Term:</strong> Local allocation</I> means that the memory required fora variable or object is obtained from the program's stack.</P><P><strong>New Term:</strong> The <I>stack</I> is an area of working memory set aside bythe program when the program starts.</P><P>Any memory the program needs for things such as local variables, function calls,and so on is taken from the program's stack. This memory is allocated as needed andthen freed when it is no longer needed; usually this happens when the program entersa function or other local code block. Memory for any local variables the functionuses is allocated when the function is entered. When the function returns, all thememory allocated for the function's use is freed. It all happens for you automatically;you don't have to give any thought to how the memory is freed or whether the memoryis freed at all.</P><P>Local allocation has its good points and its bad points. On the plus side, memorycan be allocated from the stack very quickly. The negative side is that the stackis a fixed size and cannot be changed as the program runs. If your program runs outof stack space, weird things start to happen. Your program might crash, it mightstart behaving oddly, or it might seem to perform normally but crash when the programterminates. This is less of a problem in the 32-bit world than in 16-bit programming,but it's still a consideration.</P><P>For things like variables of the built-in data types and small arrays, there isno point in doing anything other than local allocation. But if you are going to beusing large records, you will probably want to use dynamic allocation from the heap.The heap amounts to your computer's free physical RAM plus all your free hard diskspace. In other words, you can easily have 100MB of heap memory available on a typicalWindows system. The good news here is that you have virtually unlimited memory availablefor your programs. The bad news is that memory allocated dynamically requires someadditional overhead and, as such, is just a smidgen slower than memory allocatedfrom the stack. In most programs the extra overhead is not noticed in the least.An additional drawback of dynamic allocation is that it requires more from the programmer--nota lot more, mind you, but a little.</P><P><I><strong>New Term:</strong> Dynamic allocation</I> means that memory required for anobject is allocated from the heap.</P><P><PRE><strong>New Term:</strong> The <I>heap</I> in a Windows program refers to all of your computer's virtual memory.</PRE><H3><A NAME="Heading7"></A>Dynamic Allocation and Pointers</H3><P>In an Object Pascal program, memory can be allocated dynamically in several differentways. Perhaps the best way is to use the AllocMem function. AllocMem allocates memoryand fills the allocated memory with zeros. (Other ways to dynamically allocate memoryinclude the GetMem procedure and the New function.) All things considered, AllocMemprobably provides the best way of allocating memory dynamically. Let's go back tothe TMailingListRecord record. In previous examples, I allocated memory for one ofthese records from the stack like this:</P><P><PRE>var MLRecord : TMailingListRecord;begin { Fill MLRecord with data. } MLRecord.FirstName := `Per'; MLRecord.LastName := `Larsen'; { etc. } end;</PRE><P>Now I'll create the record dynamically rather than locally:</P><P><PRE>var APtr : PMailingListRecord;begin APtr := AllocMem(SizeOf(TMailingListRecord));APtr.FirstName := `Per'; APtr.LastName := `Larsen'; { Do some other things. } FreeMem(APtr);</PRE><P><B>end;</B></P><P>Notice that this time I declare a PMailingListRecord (a pointer to a TMailingListRecord)rather than a TMailingListRecord itself. Also notice that I allocate memory for thestructure by calling the AllocMem function. The parameter passed to AllocMem is theamount of memory to allocate. The SizeOf function returns the size of the record,so I use that function to determine how much memory to allocate. The call to AllocMemallocates memory and initializes the pointer by creating a new instance of a TMailingListRecorddynamically. After the memory has been allocated, you can use the pointer variablejust as you do a regular variable. Finally, notice that after I am done with theobject, I free the memory associated with the object by using the FreeMem procedure.Failure to call FreeMem to free dynamically allocated objects will result in a programthat leaks memory (uses up memory that it never releases).</P><P>This is the process by which you dynamically create and access records in ObjectPascal. You probably won't use dynamic allocation very much, but sometimes it's necessary,so you should know how it's done.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> Dynamic allocation of memory for records and arrays is optional. It is mandatory for classes. I'll discuss that in just a bit when I talk about classes. <HR></P> <P><HR><strong>NOTE:</strong> The nil keyword is used to specify a pointer that has no value. If you want to clear a pointer of its value, you use the nil keyword like this:</P> <PRE>SomePointer := nil;</PRE></BLOCKQUOTE><PRE></PRE><BLOCKQUOTE> <P>You can also use nil to test a pointer to see whether it has been allocated: <HR></BLOCKQUOTE><PRE>if SomePointer = nil then SomePointer := AllocMem(Size);</PRE><PRE>This code checks a pointer to see whether it has been assigned a value. If it hasn't been assigned a value, then memory is allocated for the pointer. </PRE><H3><A NAME="Heading8"></A>Dereferencing a Pointer</H3><P>Sometimes you need to dereference a pointer.</P><P><strong>New Term:</strong> <I>Dereferencing</I> a pointer means retrieving the objectthat the pointer points to.</P><P>Let's say that you dynamically created a mailing list record as described earlier.Now you want to assign the contents of that mailing list record to another mailinglist record variable that was allocated from the stack. Here's what you have so far:</P><P><PRE>var APtr : PMailingListRecord; Rec : TMailingListRecord;begin APtr := AllocMem(SizeOf(TMailingListRecord));</PRE><P>Now let's say you want to copy the contents of APtr to the Rec variable. The APtrvariable is a pointer to a TMailingListRecord and the Rec variable is a TMailingListRecord.You might try this:</P><P><PRE>Rec := APtr;</PRE><PRE>That won't work, however, because APtr contains a memory address, not a TMailingListRecord. In order to make this assignment, you have to dereference the pointer by using the pointer operator (^). It looks like this:</PRE><PRE>Rec := APtr^;</PRE><P>When you dereference a pointer, you are telling the compiler, "Give me theobject pointed to by the pointer and not the value of the pointer itself."</P><P><H2><A NAME="Heading9"></A>What's a Class?</H2><P>A <I>class</I> is a collection of fields and methods (functions and procedures)that work together to accomplish a specific programming task. In this way a classis said to <I>encapsulate</I> the task. Classes have the following features:</P><UL> <LI>The capability to control access <P> <LI>Constructors <P> <LI>Destructors <P> <LI>Fields <P> <LI>Methods (procedures and functions)<BR> <BR> <LI>A hidden, special pointer called Self</UL><PRE>Before diving into an explanation of these features, let me give you a quick example of how a class might be used. Let's use a typical Windows control as an example--a check box, for instance. A class that represents a check box would have fields for the caption of the check box and for the state (checked or unchecked). This class would also have methods that enable you to set and query both the check box caption and the check state. These methods might be named GetCheck, SetCheck, GetCaption, and SetCaption. After the class has been written, you can create an instance of the class to control a check box in Windows. (It's not quite that simple, but this is just an example after all.) If you have three check boxes, you would have three instances of the CheckBox class that could then be used to control each check box individually.</PRE><PRE>var Check1 : TMyCheckBox; Check2 : TMyCheckBox; Check3 : TMyCheckBox;begin Check1 := TMyCheckBox.Create(ID_CHECK1); Check2 := TMyCheckBox.Create(ID_CHECK2); Check3 := TMyCheckBox.Create(ID_CHECK3); Check1.SetCaption(`Thingamabob Option'); Check1.SetCheck(True); Check2.SetCaption(`Doohickey Options'); Check2.SetCheck(False); Check3.SetCaption(`Whodyacallum Options'); Check3.SetCheck(True); if Check1.GetCheck then DoThingamabobTask; if Check2.GetCheck then DoDoohickeyTask; { etc. } end;</PRE><P>In this example, each instance of the class is a separate object. Each instancehas its own fields, and the objects operate independently of one another. They areall objects of the same type but are separate instances in memory. With that briefintroduction, you can roll up your sleeves once more and go to work on understandingclasses.</P><BLOCKQUOTE> <P><HR><strong>NOTE:</strong> The previous example might have been more clear if I had used properties rather than methods called SetCheck, GetCheck, and SetCaption. I didn't because I'm not ready to talk about properties in detail at this time. In fact, most of this chapter will talk about classes without much emphasis on properties. I'll talk about properties more on Day 5. <HR></BLOCKQUOTE><H2><A NAME="Heading10"></A>Anatomy of a Class</H2><P>A class, like a record, has a declaration. The class declaration is always ina type section.</P><P><H2><A NAME="Heading11"></A>Class Access Levels</H2><P>Classes can have four levels of access:</P><UL> <LI>Private <P> <LI>Public <P> <LI>Protected <P> <LI>Published</UL><P>Each of these access levels is defined in this section.</P><P>Class access levels control how a class is used. As a single programmer, you mightbe not only the class's creator but also a user of the class. In team programmingenvironments, one programmer might be the creator of the class and other programmersthe users of the class. To understand the role that levels of access play in classoperation, you first need to understand how classes are used.</P><P>In any class there is the <I>public</I> part of the class, which the outside worldhas access to, and there is the private part of a class. The <I>private</I> partof a class is the internal implementation of the class--the inner workings, so tospeak.</P><P>Part of a well-designed class includes hiding anything from public view that theuser of the class doesn't need to know.</P><P><strong>New Term:</strong> <I>Data abstraction</I> is the hiding of internal implementationswithin the class from outside views.</P><P>Data abstraction prevents the user from knowing more than he or she needs to knowabout the class and also prevents the user from messing with things that shouldn'tbe messed with. For example, when you get in your car and turn the key to start it,do you want to know every detail about how the car operates? Of course not. You onlywant to know as much as you need to know to operate the car safely. In this analogy,the steering wheel, pedals, gear shift lever, speedometer, and so on represent thepublic interface between the car and the driver. The driver knows which of thosecomponents to manipulate to make the car perform the way he or she wants.</P><P>Conversely, the engine, drive train, and electrical system of the car are hiddenfrom public view. The engine is tucked neatly away where you never have to look atit if you don't want to. It's a detail that you don't need to know about, so it ishidden from you--kept private, if you prefer. Imagine how much trouble driving wouldbe if you had to know everything the car was doing at all times: Is the carburetorgetting enough gas? Does the differential have enough grease? Is the alternator producingadequate voltage for both the ignition and the radio to operate? Are the intake valvesopening properly? Who needs it! In the same way, a class keeps its internal implementationprivate so the user of the class doesn't have to worry about what's going on underthe hood. The internal workings of the class are kept private and the user interfaceis public.</P><P>The <I>protected</I> access level is a little harder to explain. Protected classmembers, like private class members, cannot be accessed by users of the class. Theycan, however, be accessed by classes that are derived from this class. Continuingwith the car analogy, let's say you want to extend the car (literally) by makingit a stretch limousine. To do this, you need to know something about the underlyingstructure of the car. You need to know how to modify the drive shaft and frame ofthe car at the very minimum. In this case you would need to get your hands dirtyand, as a limousine designer, get at the parts of the car that were previously unimportantto you (the protected parts).</P><P>The internal workings of the engine are still kept private because you don't needto know how the engine works to extend the frame of the car. Similarly, most of thepublic parts of the car remain the same, but you might add some new public elementssuch as the controls for the intercom system. I've strayed a little here and givenyou a peek in to what is called <I>inheritance</I>, but I won't go in to furtherdetails right now. I will talk more about protected access a little later in thesection "Methods," and about inheritance in the section "Inheritance."The point here is that the protected section of a class contains the parts of a classthat someone extending the class will need to know about.</P><P>The <I>published</I> access level is used when writing components. Any componentsdeclared in the published section will appear in the Object Inspector at design time.I'll talk more about the published section on Day 20, "Creating Components."</P><P>The Object Pascal language has four keywords that pertain to class access. Thekeywords are (not surprisingly) public, private, protected, and published. You specifya class member's access level when you declare the class. A class is declared withthe class keyword. Here's an example:</P><P><PRE>TVehicle = classprivateCurrentGear : Integer; Started : Boolean;</PRE><P><B>Speed : Integer;</B></P><P><PRE> procedure StartElectricalSystem; procedure StartEngine;protected
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -