LABORATORY
9 Getting classy
Objectives
Objects are the
basic unit of programming in object-oriented languages like C++. The C++ construct for
defining new types of objects is the class. A class is the ÒblueprintÓ from
which an object can be created. This laboratory examines the basic mechanisms
of class types by inspecting several different classes.
Key
Concepts
_ class construct
- Access specification
- Information hiding
- Constructors
- Encapsulation
- Inspectors
- Data members
- Mutators
- Facilitators
GETTING
STARTED
Copy the necessary
files to your directory, you will use them for this lab.
cp
ÐRp ~goldwasser/csp125/labs/lab09 .
Circle
Class
Objects are the
fundamental units of programming in object-oriented languages such as C++. Objects are
models of information and are implemented as software packages that contain or encapsulate both attributes and behavior. A data
abstraction is a representation of information and the operations to be
performed on it. A fundamental type is a type that the programming language
provides. For example, in C++, the type int and the operations on it are part of the language definition. That
is, all C++ compilers must provide int objects. In
addition to the fundamental types, C++ provides several
mechanisms to define other types. These other types are called programmer- or user-defined
types. The class construct is the most important mechanism for defining
new types. With this construct, software engineers can define encapsulated
objects. When defining a class, we typically use the information-hiding
principle: All interaction with an object should be constrained to use a well
defined interface that allows underlying object implementation details to be
safely ignored.
By following the
information-hiding principle, we can create classes that tend to be reliable
and easily reused. To consider the basics of creating a new object type using
the class construct, we first examine the declaration of a
programmer-definedÑCircle. Whenever one is designing something, it helps to know how the
thing will be used. Our goal in designing the class Circle is to create an
object that is both easy to construct and simple to use. The first thing to do
when creating a class-type object is to determine the attributes of the object.
For circle objects, the necessary attributes are its center and its radius. In C++, the attributes
of a class-type object are referred to as the data members. The following
are the declarations of the data members of Circle:
float x;
float y;
float radius;
The second step
when creating a class-type object is to determine the messages the object can
receive and the operations that can be performed on the object. This portion of
an object is called its behavior component. The behavior component of a class-type
object is a collection of member functions that provide
the ability to
send messages to the object requesting it to perform some action. These member
functions provide the public interface to achieve the desired behavior; other
member functions are often present to assist the member functions that are part
of the public interface.
For a circle
class, we can divide the messages that a circle needs to handle into three sets. One set of messages directs
a Circle object to return an attributeÕs value. The second set of messages
directs a Circle object to change the value of an attribute. The third set of
messages directs a Circle object to perform a service.
Messages that
return the value of an attribute are called inspectors. For maximum
flexibility, our definition of Circle includes inspectors for all of the data
members. Inspectors will have the
qualifier const after their parameter list. The qualifier indicates
that the member function does not modify the object. An inspector name usually
begins with Get.
Messages that
change or set an attribute are called mutators. Again, to make
the Circle as flexible as possible, we will have mutators for the attributes
that control the size and location of a Circle.
There are class
member functions that are neither inspectors nor mutators. The getArea messages
tells the circle to display its area. getArea() is an example of a
facilitator. A facilitator performs a service. In addition to the
class member functions that process messages, a class definition will also
specify class constructors.
A constructor is a member
function that initializes an object of that class. A constructor has the same
name as the class. The appropriate constructor is invoked automatically when a Circle object is
defined. The following Circle constructor
expects an initial value for each of the data members. Unlike other functions,
a constructor does not have a return type.
Circle(float cx,
float cy, float rad);
Besides listing
the various members, the definition of a class also indicates which parts of a
program can use the members. There are three kinds of access permissions: public, private, and protected. The general rule
is
A public member has
unrestricted access.
A private member
can be accessed only by other members of the same class.
We will talk about protected later in the course.
_ Open the file Circle.h to see the class
definition for Circle. It should resemble the following:
#ifndef
_CIRCLE_H
#define
_CIRCLE_H
class Circle
{
public:
Circle();
Circle(float cx, float cy, float r);
void Set_x(float cx);
void Set_y(float cy);
void Set_radius(float r);
float Get_x();
float Get_y();
float Get_radius();
float Get_Area();
float Get_Perimeter();
bool Overlap(Circle mycircle);
private:
float x;
float y;
float radius;
};
#endif
_ Examine the code. If
you are unsure about any aspects of the definition of class Circle, consult your
laboratory instructor before proceeding
Modify the program mycircle.cpp by defining a second Circle object yourcircle. Have yourcircle be different in size and position from the
Circle object already defined in the program. Make a second call
getArea() to also display the area of yourcircle.
TO COMPILE your
program use the following syntax:
g++
Circle.cpp mycircle.cpp ÐWall Ðpedantic Ðansi Ðo circles
./circles
The member
function overlap checks if 2 circles overlap Ð call this function using mycircle
and yourcircle to see if they overlap.
Recompile and test your program.
Submit your
updated mycircle.cpp file.
When defining a
class, we give the public section first because the members in this section can
be used by anyone. The private section comes last.
Open the file
Circle.cpp.
Observe that the
class name and the scope resolution operator precede the member function name.
Note that the scope resolution operator is a double colon (::). The member
functions must be identified this way so that the compiler can tell that they
belong to a class. The first function defined in the file is a Circle constructor. A
constructor for a class is invoked when an object of that class is defined.
_ To verify that the
Circle constructor is invoked when a Circle object is defined,
add an insertion statement in CircleÕs constructor that inserts the following
message to the stream cout:
Circle
constructor called.
You may wonder why
the constructor uses the mutators to set the values of the data members when
the constructor could access the data members directly. The key idea is that
all access to the data members should be through the same interface (i.e.,
member function). Thus a client user of a class changes the data members the
same way a public member function of the class changes them. Using this
strategy means that we can change the representation of a data member without
having to modify every class member function that changes the value of the data
member. Since all access to the data member is through the mutator, we need to
change only the implementation of the mutator. This concept is probably fuzzy
because you have not yet seen enough code to appreciate this very important
design strategy. However, as you develop additional classes and modify existing
classes, you will see that always using a mutator to change a data member value
(whether the entity doing the changing is a client user of the class or a
member function of the class) makes software more flexible, easier to maintain,
and easier to modify.
Using Classes
Complex Numbers
Open the file
Complex.h. This contains the class
interface for a class Complex which represents complex number.
Open the program
called complex_numbers.cpp, you will need to complete the implementation. You need to begin by declaring two
Complex object, then accepting
values for the real and imaginary parts from the user and sets up the
numbers. Then the program should
calculate (using the member functions) and output the sum of the two complex
numbers and the difference between them (subtract the second number from the
first one).
To compile this
program use the following syntax
%g++
Complex.cpp complex_numbers.cpp Ðo complex ÐWall Ðansi Ðpedantic
%./complex
Upload your
modified complex_numbers.cpp file.
Banking
Open the file
BankAccount.h. This contains the
class interface for a class BankAccount.
It looks like this:
//Program to
demonstrates the class BankAccount.
#ifndef
_BANKACCOUNT_H
#define
_BANKACOUNT_H
#include
<iostream>
using namespace
std;
//Class for a
bank account:
class BankAccount
{
public:
BankAccount();
BankAccount(int dollars,
int cents, double rate);
//Postcondition: The
account balance has been set to $dollars.cents;
//The interest rate has
been set to rate percent.
BankAccount(int dollars,
double rate);
//Postcondition: The
account balance has been set to $dollars.00.
//The interest rate has
been set to rate percent.
void set(int dollars, int
cents, double rate);
//Postcondition:The account
balance has been set to $dollars.cents;
//The interest rate has been set
to rate percent.
void set(int dollars,
double rate);
//Postcondition: The account
balance has been set to $dollars.00.
//The interest rate has been set
to rate percent.
void update( );
//Postcondition: One year
of simple interest has been
//added to the account
balance.
double get_balance( );
//Returns the current
account balance.
double get_rate( );
//Returns the current
account interest rate as a percent.
void output(ostream&
outs);
//Precondition: If outs is
a file output stream, then
//outs has already been
connected to a file.
//Postcondition: Account
balance and interest rate have
//been written to the
stream outs.
private:
double balance;
double interest_rate;
double fraction(double
percent);
//Converts a percent to a
fraction.
//For example,
fraction(50.3) returns 0.503.
};
#endif
Open the program
banking.cpp. There are several
tasks for you to complete, using the member functions declared in the
interface. Once complete compile
and run the program using
%g++
BankAccount.cpp banking.cpp ÐWall Ðpedantic Ðansi Ðo banking
%./banking
Next open
BankAccount.cpp Ð examine each member function and ensure you know what is
going on, if you have any questions discuss this with your lab instructor.
Upload your
modified banking.cpp file.
Finishing up.
The files you need
to have uploaded along the way are your updated versions of
mycircle.cpp
complex_numbers.cpp
banking.cpp
Thank your Lab Instructor!