📄 chap06.txt
字号:
Chapter 6
MORE ENCAPSULATION
The purpose of this chapter is to illustrate how to use some of the
traditional aspects of C or C++ with classes and objects. Pointers
to an object as well as pointers within an object will be
illustrated. Arrays embedded within an object, and an array of
objects will be illustrated. Since objects are simply another C++
data construct, all of these things are possible and can be used
if needed.
In order to have a systematic study, we will use the program named
BOXES1.CPP from the last chapter as a starting point and we will
add a few new constructs to it for each example program. You will
recall that it was a very simple program with the class definition,
the class implementation, and the main calling program all in one
file. This was selected as a starting point because we will
eventually make changes to all parts of the program and it will be
convenient to have it all in a single file for illustrative
purposes. It must be kept in mind however that the proper way to
use these constructs is to separate them into the three files as
was illustrated in BOX.H, BOX.CPP, and BOXES2.CPP in the last
chapter. This allows the implementor of box to supply the user
with only the interface, namely BOX.H. Not giving him the
implementation file named BOX.CPP, is practicing the technique of
information hiding.
As we have said many times, it seems silly to break up such a small
program into three separate files, and it is sort of silly. The
last chapter of this tutorial will illustrate a program large
enough to require dividing the program up into many separate files.
AN ARRAY OF OBJECTS
_________________________________________________________________
Examine the file named OBJARRAY.CPP for our ================
first example of an array of objects. This file OBJARRAY.CPP
is nearly identical to the file named BOX1.CPP ================
until we come to line 44 where an array of 4
boxes are declared.
Recalling the operation of the constructor you will remember that
each of the four box objects will be initialized to the values
defined within the constructor since each box will go through the
constructor as they are declared. In order to declare an array of
objects, a constructor for that object must not require any
parameters. (We have not yet illustrated a constructor with
initializing parameters, but we will in the next program.) This
Page 6-1
Chapter 6 - More Encapsulation
is an efficiency consideration since it would probably be an error
to initialize all elements of an array of objects to the same
value. We will see the results of executing the constructor when
we compile and execute the file later.
Line 49 defines a for loop that begins with 1 instead of the normal
starting index for an array leaving the first object, named
group[0], to use the default values stored when the constructor was
called. You will observe that sending a message to one of the
objects uses the same construct as is used for any object. The
name of the array followed by its index in square brackets is used
to send a message to one of the objects in the array. This is
illustrated in line 50 and the operation of that code should be
clear to you. The other method is called in the output statement
in lines 57 and 58 where the area of the four boxes in the group
array are listed on the monitor.
Another fine point should be pointed out. The integer variable
named index is declared in line 49 and is still available for use
in line 56 since we have not yet left the enclosing block which
begins in line 43 and extends to line 65.
DECLARATION AND DEFINITION OF A VARIABLE
_________________________________________________________________
An extra variable was included for illustration, the one named
extra_data in line seven. Since the keyword static is used to
modify this variable in line 7, it is an external variable and only
one copy of this variable will ever exist. All seven objects of
this class share a single copy of this variable which is global to
the objects defined in line 44.
The variable is actually only declared here which says it will
exist somewhere, but it is not defined. A declaration says the
variable will exist and gives it a name, but the definition
actually defines a place to store it somewhere in the computers
memory space. By definition, a static variable can be declared in
a class header but it cannot be defined there, so it is defined
somewhere outside of the header, usually in the implementation
file. In this case it is defined in line 16 and can then be used
throughout the class.
Line 23 of the constructor sets the single global variable to 1
each time an object is declared. Only one assignment is necessary
so the other six are actually wasted code. To illustrate that
there is only one variable shared by all objects of this class,
the method to read its value also increments it. Each time it is
read in lines 60 through 64, it is incremented and the result of
the execution proves that there is only a single variable shared
by all objects of this class. You will also note that the method
named get_extra() is defined within the class declaration so it
will be assembled into the final program as inline code.
Page 6-2
Chapter 6 - More Encapsulation
Be sure you understand this program and especially the static
variable, then compile and execute it to see if you get the same
result as listed at the end of the program.
A STRING WITHIN AN OBJECT
_________________________________________________________________
Examine the program named OBJSTRNG.CPP for our ================
first example of an object with an embedded OBJSTRNG.CPP
string. Actually, the object does not have an ================
embedded string, it has an embedded pointer, but
the two work so closely together that we can
study one and understand both.
You will notice that line 7 contains a pointer to a string named
line_of_text. The constructor contains an input parameter which
is a pointer to a string which will be copied to the string named
line_of_text within the constructor. We could have defined the
variable line_of_text as an actual array in the class, then used
strcpy() to copy the string into the object and everything would
have worked the same, but we will leave that as an exercise for you
at the end of this chapter. It should be pointed out that we are
not limited to passing a single parameter to a constructor. Any
number of parameters can be passed, as will be illustrated later.
You will notice that when the three boxes are declared this time,
we supply a string constant as an actual parameter with each
declaration which is used by the constructor to assign the string
pointer some data to point to. When we call get_area() in lines
48 through 53, we get the message displayed and the area returned.
It would be prudent to put these operations in separate methods
since there is no apparent connection between printing the message
and calculating the area, but it was written this way to illustrate
that it can be done. What this really says is that it is possible
to have a method that has a side effect, the message output to the
monitor, and a return value, the area of the box. However, as we
discussed in chapter 4 when we studied DEFAULT.CPP, the order of
evaluation is sort of funny, so we broke each line into two lines.
After you understand this program, compile and execute it.
AN OBJECT WITH AN INTERNAL POINTER
_________________________________________________________________
The program named OBJINTPT.CPP is our first ================
example program with an embedded pointer which OBJINTPT.CPP
will be used for dynamic allocation of data. ================
In line 7 we declare a pointer to an integer
variable, but it is only a pointer, there is no storage associated
with it. The constructor therefore allocates an integer type
Page 6-3
Chapter 6 - More Encapsulation
variable on the heap for use with this pointer in line 21. It
should be clear to you that the three objects created in line 45
each contain a pointer which points into the heap to three
different locations. Each object has its own dynamically allocated
variable for its own private use. Moreover each has a value of 112
stored in its dynamically allocated data because line 22 stores
that value in each of the three locations, once for each call to
the constructor.
In such a small program, there is no chance that we will exhaust
the heap, so no test is made for unavailable memory. In a real
production program, it would be expedient to test that the value
of the returned pointer is not NULL to assure that the data
actually did get allocated.
The method named set() has three parameters associated with it and
the third parameter is used to set the value of the new dynamically
allocated variable. There are two messages passed, one to the
small box and one to the large box. As before, the medium box is
left with its default values.
The three areas are displayed followed by the three stored values
in the dynamically allocated variables, and we finally have a
program that requires a destructor in order to be completely
proper. If we simply leave the scope of the objects as we do when
we leave the main program, we will leave the three dynamically
allocated variables on the heap with nothing pointing to them.
They will be inaccessible and will therefore represent wasted
storage on the heap. For that reason, the destructor is used to
delete the variable which the pointer named point is referencing
as each object goes out of existence. In this case, lines 37 and
38 assign values to variables that will be automatically deleted.
Even though these lines of code really do no good, they are legal
statements.
Actually, in this particular case, the variables will be
automatically reclaimed when we return to the operating system
because all program cleanup is done for us at that time. If this
were a function that was called by another function however, the
heap space would be wasted. This is an illustration of good
programming practice, that of cleaning up after yourself when you
no longer need some dynamically allocated variables.
One other construct should be mentioned once again, that of the
inline method implementations in line 11 and 12. As we mentioned
in chapter 5 and repeated earlier in this chapter, inline functions
can be used where speed is of the utmost in importance since the
code is assembled inline rather than by actually making a method
call. Since the code is defined as part of the declaration, the
system will assemble it inline, and a separate implementation for
these methods is not needed. If the inline code is too involved,
the compiler is allowed to ignore the inline request and will
actually assemble it as a separate method, but it will do it
invisibly to you and will probably not even tell you about it.
Page 6-4
Chapter 6 - More Encapsulation
Remember that we are interested in using information hiding and
inline code prevents hiding of the implementation, putting it out
in full view. Many times you will be more interested in speeding
up a program than you are in hiding a trivial implementation.
Since most inline methods are trivial, feel free to use the inline
code construct.
Be sure to compile and execute this program.
A DYNAMICALLY ALLOCATED OBJECT
_________________________________________________________________
Examine the file named OBJDYNAM.CPP for our ================
first look at a dynamically allocated object. OBJDYNAM.CPP
This is not any different than any other ================
dynamically allocated object, but an example is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -