📄 chap05.htm
字号:
<P>Example program ------> <B><A HREF="OPENPOLE.CPP">OPENPOLE.CPP</A></B>
<P>Examine the program named OPENPOLE.CPP for an example of a program with
a few serious problems that will be overcome in the next example program
by using the principles of encapsulation.
<P>We have two structures declared, one being a <B>rectangle </B>and the
other a <B>pole</B>. The data fields should be self explanatory with the
exception of the <B>depth </B>of the <B>flagpole </B>which is the depth
it is buried in the ground, the overall length of the pole is therefore
the sum of the <B>length </B>and the <B>depth</B>.
<P><IMG SRC="CPP0504.GIF" HSPACE=20 VSPACE=20 BORDER=0 HEIGHT=183 WIDTH=390>
<BR>Figure 5-4 depicts the data space for this program after execution
of line 34. Based on your experience with ANSI-C, you should have no problem
understanding exactly what this program is doing, but you may be a bit
confused at the meaning of the result found in line 40 where we multiply
the <B>height </B>of the <B>square </B>with the <B>width </B>of the <B>box</B>.
This is perfectly legal to do in ANSI-C or C++, but the result has no earthly
meaning because the data are for two different entities. Likewise, the
result calculated in line 42 is even sillier because the product of the
<B>height </B>of the <B>square </B>and the <B>depth </B>of the <B>flagpole
</B>has absolutely no meaning in any physical system we can think up. The
error is obvious in a program as simple as this, but in a large production
program it is very easy for such problems to be inadvertently introduced
into the code and the errors can be very difficult to find.
<P>Wouldn't it be neat if we had a way to prevent such stupid things from
happening in a large production program. If we had a good program that
defined all of the things we can do with a <B>square </B>and another program
that defined everything we could do with a <B>pole</B>, and if the data
could be kept mutually exclusive, we could prevent these silly things from
happening. If these entities must interact, they cannot be put into separate
programs, but they can be put into separate classes to achieve the desired
goal.
<P>It should come as no real surprise to you that the next program will
do just those things for us and do it in a very elegant way. Before proceeding
on to the next example program, you should compile and execute this one
even though it displays some silly results.
<P><B>OBJECTS PROTECT DATA</B>
<P>Example program ------> <B><A HREF="CLASPOLE.CPP">CLASPOLE.CPP</A></B>
<P>Examine the program named CLASPOLE.CPP as an example of data protection
in a very simple program.
<P>In this program, the <B>rectangle </B>is changed to a <B>class </B>with
the same two variables which are now <B>private</B>, and two methods which
can manipulate the private data. One method is used to initialize the values
of the objects created and the other method returns the area of the object.
The two methods are defined in lines 13 through 22 in the manner described
earlier in this chapter. The pole is left as a structure to illustrate
that the two can be used together and that C++ is truly an extension of
ANSI-C.
<P><IMG SRC="CPP0505.GIF" HSPACE=20 VSPACE=20 BORDER=0 HEIGHT=219 WIDTH=507>
<P>In line 35 we define two objects, once again named <B>box </B>and <B>square</B>,
but this time we cannot assign values directly to their individual components
because they are private elements of the class. Figure 5-5 is a graphical
illustration of the two objects available for use within the calling program.
Lines 38 through 40 are commented out for that reason and the messages
are sent to the objects in lines 42 and 43 to tell them to initialize themselves
to the values input as parameters. The <B>flag_pole</B> is initialized
in the same manner as in the previous program. Using the class in this
way prevents us from making the silly calculations we did in the last program,
because we can only calculate the area of an object by using the data stored
within that object. The compiler is now being used to prevent the erroneous
calculations. The end result is that the stupid calculations we did in
the last program are not possible in this program, so lines 52 through
55 have been commented out. Once again, it is difficult to see the utility
of this in such a simple program. In a large program, using the compiler
to enforce the rules can pay off in a big way.
<P>Even though the <B>square </B>and the <B>box </B>are both objects of
class <B>rectangle</B>, their private data is hidden from each other such
that neither can purposefully or accidentally change the other's data.
<P>This is the abstract data type mentioned earlier in this chapter, a
model with a set of private variables for data storage and a set of operations
that can be performed on that stored data. The only operations that can
be performed on the data are those defined by the methods, which prevents
many kinds of erroneous or silly operations. Encapsulation and data hiding
bind the data and procedures, or methods, tightly together and limit the
scope and visibility of each. Once again, we have the divide and conquer
technique in which an object is separated from the rest of the code and
carefully developed in complete isolation from it. Only then is it integrated
into the rest of the code with a few very simple interfaces.
<P>Someone did a study several years ago in which they determined that
programmers accidentally corrupted data much more often than they accidentally
corrupted code. So it was determined that if the data could be protected
from accidental corruption, the quality of the software could be improved.
This is where the idea of information hiding originated and it has proven
itself to be very valuable over the years.
<P><B>HAVE YOU EVER USED THIS TECHNIQUE BEFORE?</B>
<P>A good example of the use of this technique is in the file commands
you have been using with ANSI-C. The data in the file is only available
through the predefined functions provided by your compiler writer. You
have no direct access to the actual data because it is impossible for you
to address the actual data stored on the disk. The data is therefore private
data, as far as you are concerned, but the available functions are very
much like methods in C++.
<P>There are two aspects of this technique that really count when you are
developing software. First, you can get all of the data you really need
from the file system because the interface is complete, but secondly, you
cannot get any data that you do not need. You are prevented from getting
into the file handling system and accidentally corrupting some data stored
within it. You are also prevented from using the wrong data because the
functions available demand a serial access to the data. I should mention
that this is a very weak example because it is very easy for a knowlegeable
C programmer to break the encapsulation provided by the file system.
<P>Another example of weak encapsulation is the monitor and keyboard handling
routines. You are prevented from getting into the workings of them and
corrupting them accidentally, but you are provided with all of the data
interfaces that you really need to effectively use them.
<P>Suppose you are developing a program to analyze some characteristics
of flagpoles. You would not wish to accidentally use some data referring
to where the flagpole program was stored on your hard disk as the height
of the flagpole, nor would you wish to use the cursor position as the flagpole
thickness or color. All code for the flagpole is developed alone, and only
when it is finished, is it available for external use. When using it, you
have a very limited number of operations which you can do with the class.
The fact that the data is hidden from you protects you from accidentally
doing such a thing when you are working at midnight to try to meet a schedule.
Once again, this is referred to as information hiding and is one of the
primary advantages of object oriented programming over procedural techniques.
<P>Based on the discussion given above you can see that object oriented
programming is not really new, since it has been used in a small measure
for as long as computers have been popular. The newest development, however,
is in allowing the programmer to partition his programs in such a way that
he too can practice information hiding to reduce the debugging time and
improve the quality of his software.
<P><B>WHAT DOES THIS COST?</B>
<P>It should be clear that this technique will cost you something in efficiency
because every access to the elements of the object will require the time
and inefficiency of a call to a function, or perhaps I should be more proper
and refer to it as a method. The time saved in building a large program,
however, could easily be saved in debug time when it comes time to iron
out the last few bugs. This is because a program made up of objects that
closely match the application are much easier to understand than a program
that does not.
<P>This is obviously such a small program that it is silly to try to see
any gain with this technique. In a real project however, it could be a
great savings if one person developed all of the details of the rectangle,
programmed it, and made it available to you to simply use. This is exactly
what has been done for you if you consider the video monitor an object.
There is a complete set of preprogrammed and debugged routines you can
use to make the monitor do anything you wish it to do, all you have to
do is study the interface to the routines and use them, expecting them
to work. You have no need to study the implementation, nor are you required
to understand it, provided that it works. As we mentioned earlier, it is
impossible for you to multiply the size of your monitor screen by the depth
of the flag pole because that information is not available to you to use
in a corruptible way.
<P>After you understand some of the advantages of this style of programming,
be sure to compile and execute this program.
<P><B>CONSTRUCTORS AND DESTRUCTORS</B>
<P>Example program ------> <B><A HREF="CONSPOLE.CPP">CONSPOLE.CPP</A></B>
<P>The file named CONSPOLE.CPP introduces constructors and destructors
and should be examined at this time.
<P>This example program is identical to the last example except that a
constructor has been added as well as a destructor. The constructor always
has the same name as the class itself and is declared in line 9, then defined
in lines 15 through 19. The constructor is called automatically by the
C++ system when the object is declared and prevents the use of an uninitialized
variable. When the object named <B>box </B>is defined in line 48, the constructor
is called automatically by the system. The constructor sets the values
of <B>height </B>and <B>width </B>each to 6 in the object named <B>box</B>.
This is printed out for reference in lines 51 and 52. Likewise, when the
<B>square </B>is defined in line 48, the values of the <B>height </B>and
the <B>width </B>of the <B>square </B>are each initialized to 6 when the
constructor is called automatically.
<P>A constructor is defined as having the same name as the class itself.
In this case both are named <B>rectangle</B>. The constructor cannot have
a return type associated with it because of the definition of C++. It actually
has a predefined return type, a pointer to the object itself, but we will
not be concerned about this until much later in this tutorial. Even though
both objects are assigned values by the constructor, they are initialized
in lines 60 and 61 to new values and processing continues. Since we have
a constructor that does the initialization, we should probably rename the
method named <B>initialize()</B> something else but it illustrates the
concept involved here.
<P>The destructor is very similar to the constructor except that it is
called automatically when each of the objects goes out of scope. You will
recall that automatic variables have a limited lifetime because they cease
to exist when the enclosing block in which they were declared is exited.
When an object is about to be automatically deallocated, its destructor,
if one exists, is called automatically. A destructor is characterized as
having the same name as the class but with a tilde prepended to the class
name. A destructor has no return type.
<P>A destructor is declared in line 12 and defined in lines 32 through
36. In this case the destructor only assigns zeros to the variables prior
to their being deallocated, so nothing is really accomplished. The destructor
is only included for illustration of how it is used. If some blocks of
memory were dynamically allocated within an object, the destructor should
contains code to deallocate them prior to losing the pointers to them.
This would return their memory to the free store for further use later
in the program.
<P>It is interesting to note that if a constructor is used for an object
that is declared prior to the <B>main()</B> program, a global variable,
the constructor will actually be executed prior to the execution of the
<B>main()</B> program. In like manner, if a destructor is defined for such
a variable, it will execute following the completion of execution of the
<B>main()</B> program. This will not adversely affect your programs, but
it is interesting to make note of.
<P><B>OBJECT PACKAGING</B>
<P>Example program ------> <B><A HREF="BOXES1.CPP">BOXES1.CPP</A></B>
<P>Examine the file named BOXES1.CPP for an example of how not to package
an object for universal use. This packaging is actually fine for a very
small program, but is meant to illustrate to you how to split your program
up into smaller, more manageable files when you are developing a large
program or when you are part of a team developing a large system. The next
three example files in this chapter will illustrate the proper method of
packaging a class.
<P>This program is very similar to the last one with the pole structure
dropped and the class named <B>box</B>. The class is declared in lines
4 through 13, the implementation of the class is given in lines 16 through
35, and the use of the class is given in lines 38 through 52. With the
explanation we gave about the last example program, the diligent student
should have no problem understanding this program in detail.
<P><B>INLINE IMPLEMENTATION</B>
<P>The method in line 11 contains the implementation for the method as
a part of the declaration because it is very simple, and because it introduces
another new topic which you will use often in C++ programming. When the
implementation is included in the declaration, it will be assembled inline
wherever this function is called leading to much faster code. This is because
there is no function call overhead when making a call to the method. In
some cases this will lead to code that is both smaller and faster. This
is yet another illustration of the efficiency built into the C++ programming
language. Inline code implementation in C++ accomplishes the same efficiency
that the macro accomplishes in C, and is the constuct of choice for small
functions.
<P>Compile and execute this program in preparation for our study of the
next three examples which are a repeat of this program in a slightly different
form.
<P><B>THE CLASS HEADER FILE</B>
<P>Example program ------> <B><A HREF="BOX.H">BOX.H</A></B>
<P>If you examine BOX.H carefully, you will see that it is only the class
definition. No details are given of how the various methods are implemented
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -