UMBC CMSC202, Computer Science II, Spring 1998, Sections 0101, 0102,
0103, 0104 and Honors
Thursday April 2, 1998
Assigned Reading:
- A Book on C:
- Programming Abstractions in C:
Handouts (available on-line): none
Topics Covered:
- Lecture on Object-Oriented Programming (OOP).
- Object-Oriented Programming is a programming methodology that
promotes the separation of code/functions according to the type of
data that a particular piece of code works on. It is a
data-centric approach.
- In the OOP methodology, an "object" is considered an
autonomous unit. In this mode of thinking, you do not apply
functions to objects --- you ask the objects to perform some
operation on itself. For example, if the object is an integer, we
would ask the integer to increment itself rather than apply the
increment operation on the integer. This sounds silly to most
people at the beginning, but we shall see how the OOP paradigm
promotes better organization of large programs and enables code
reuse. From your experience with Project 3, it should not be
too difficult to convince you that better organization of
large programs is both desirable and necessary.
- Our first attempt at making objects.
- C++ is an extension of C. Anything you do in C, is allowed in
C++, but to take advantage of C++ and to follow an object-oriented
approach, you would do things differently in C++.
- One main difference between C++ and C is in the header files.
To define a new class of objects, you use the "class" directive. In
our first header file, we declare a
new kind of object called "Box". The "class" directive is a
combination of function prototypes and a type definition.
- In our example, the definition of the class Box includes
function prototypes for Box(), identify(),
volume(), grow(), shrink() and
random(). These are called "member functions" or
"methods" in object-oriented lingo. They are just functions.
- The definition of Box also includes data members:
length, height and width. These are
just called "members" in C++ lingo. The correspond to the idea of
fields of a record in C. For example, if b1 has type Box,
then the length field of the Box b1 can be
accessed using b1.length. However, since the length field
of Box is private, only member functions can access the length,
height and width members.
- The member functions in our Box class are implemented in a
file called Box.C. C++ programs
usually have a .C extension. On Unix, we use the CC command to
compile C++ programs. Otherwise, compiling C++ programs is
very similar to compiling C programs. Observe that the
names of the member functions in the class Box are
prefaced with "Box::" in the implementations.
- Turning to the main program
we can see how member functions in the class Box are called.
First, we need objects of type Box. In this program we create
3 objects of type Box in the statement:
Box b1, b2, b3 ;
Now, member functions can be called using the "." operator. The syntax
is the same as C syntax for a field in a record. One way to remember
the syntax for member functions is to pretend that each member function
is a field in a record. So, for example, the statement:
b1.identify() ;
calls the function identify(). In this case, the object
b1 is called the host object. You can think of this statement
as a command to the object b1 to identify itself. The
sample run demonstrates the effects of
executing our first C++ program.
- Returning to the implementations of the member functions in
the file Box.C, observe that the
function identify() refers to variables called
length, height and width. These are
members (or fields) of the host object b1. Since the
function identify was called using b1, the variable
length refers to the length member of b1
and not that of some other Box object. In other respects, member
functions are like ordinary C functions. You can have local variables,
you can have loops, you can call other functions, etc.
- The member function Box::Box is a special function
called a constructor. It is distinguished by two things. First,
the name of the function is the name of the class. Second, the
function prototype does not have a return type and is not allowed
to have a return type, not even void. This constructor is called
whenever new objects of type Box are declared. For example, in the
statement above that created three new objects b1, b2
and b3 of type Box, the Box constructor was called three times.
Each time, the Box constructor assigns random values to the
length, height and width members of the new
object. Thus, constructors provide a very convenient mechanism for
initializing objects as they are created.
- The member function random() is also different from
other member functions in our Box class. This function was
declared in the private section of the Box definition in the header file. Thus, random() can
only be called by other member functions in the Box class. So, a
function call like:
b1.random() ;
would generate an error at compile time. Similarly, the
length, height and width fields are private,
and references to them outside the member functions would cause compile
time errors. Our second main program
and sample run demonstrates this.
- Our main program using the Box
class shows that we can use the symbol "Box" like a type in a C program.
For example, we can declare an array with 4 elements of type Box using
the statement:
Box boxes[4] ;
In this case, the constructor Box::Box is called 4 times and the
members of each Box object in the array is initialized using
random() as the sample run
shows. Note that we can also declare pointers to Box, using for example:
Box *bptr ;
Here, the analogy to the syntax for fields of records in C still hold.
To refer to the member function identify(), we can dereference
the pointer to Box using then choose a field using:
(*bptr).identify() ;
or we can use the -> operator:
bptr->identify() ;
- The new operator in C++ provides functionality that
is similar to a call to malloc(). In this program, the
statement:
bptr = new Box[items] ;
creates a dynamically allocated array of Boxes. As before, each
Box object in the array is initialized by a call to the constructor
function Box::Box. If the new operator cannot
make the array for some reason (say the system is out of memory),
then it returns NULL (just like malloc()). As you would
expect, since bptr is a pointer to the first element of an
array, we can use array notation like bptr[i] to refer to
an element of the array.
- The delete operation used at the end is analogous to free. It
releases the memory that bptr points to, which was previously
allocated by the new operation.
- Our second attempt at making objects: improving the Box class.
- First, we improve the constructor function in two ways.
First, in the header file, we
define a new constructor that allows you to specify the
length, height and width of the new Box.
This is done within the definition of the Box class using the
prototype:
Box(float,float,float) ;
Note that both constructors have the same name Box.
However, the compiler is never confused about which one you intend
to call because one constructor has no parameters (the default
constructor) and the other one has 3 float parameters.
Thus, in this case the number of actual parameters in a call to the
Box constructor will determine which of the two constructors is used.
For example, in the main program, the
statement:
Box b1, b3 ;
calls the default constructor twice, whereas the statement:
Box b2 = Box(1.0, 2.0, 3.1) ;
calls the alternate constructor and creates a Box with
length=1.0, height=2.0 and width=3.1.
-
A subtle difference between C and C++. In C, we do not tend to
think of variable declarations as statements, because nothing
is executed --- the compiler is simply informed about the type
of certain variables. In C++, variable declarations create calls to
constructors, so it is better to think of them as statements.
- Another problem with our first Box class is that the
random() function is not very random. Since we did not
set the random seed for the calls to lrand48(), our calls
to lrand48() always returns the same sequence of numbers.
In order to set the random seed with a call to srand48(),
we need to know when the first call to a Box constructor occurs.
This is accomplished using a shared member called count.
In C++, a shared variable is designated by the keyword static.
Do not confuse this use of static with any other use of the
keyword static. That the member count is shared means
that there is only one copy of count for all objects of type
Box. This is very different from other members --- each Box member has
its own length, height and width. The
value of count is initialized in the implementation file
box2.C using the statement:
int Box::count = 0 ;
This statement is required. Thus, in our constructors we can use
the shared member count to keep track of the number of
Boxes that have been created. In particular, when count
is zero, we can initialize the random seed using the system clock.
This ensures that each time we run our program we have a different
sequence of random numbers. (See sample
run.)
Last Modified:
22 Jul 2024 11:27:45 EDT
by
Richard Chang
Back up
to Spring 1998 CMSC 202 Section Homepage