Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 61

Chapter XVII

Introduction to Object Oriented


Programming

Chapter XVII Topics


17.1 Introduction

17.2 A New Look at struct

17.3 The First Object Definition

17.4 From struct to class

17.5 Classes and Objects

17.6 The Step-By-Step Class

17.7 Declaring const Functions

17.8 Overloading operator+=

17.9 The Initializer List

17.1 Introduction

Chapter XVII Introduction to Object Oriented Programming 17.1


You know Object Oriented Programming (OOP) is a big deal. Many of the
popular Computer magazines talk about it. College classes teach courses about
object stuff. Computer science people talk about objects, and even people who do
not have a clue what they are talking about, talk about objects. Finally, your
teacher, and this book say that objects are a big deal. You are satisfied. The tidal
wave is simply too large and you accept the object hype. You just have one
simple, short little question.

What is OOP, and why is it a big deal?

The question is short and simple. The answer is hardly short, and it is far from
simple. Do you remember how in the previous chapter the early data structure
definition was altered by the end of the chapter. Well, in this case I am not even
going to attempt an early OOP definition. OOP is defined by a set of significant
OOP components. Each one of these components is brand-new, and needs to be
explained as well. There is no clean way to take prior knowledge - prior
vocabulary - and prior experience, and toss it together into a definition.

Does this make OOP difficult to learn? Not really. Objects are pretty neat and
provide the programmer with some powerful tools for sophisticated programs.
Like many new concepts, OOP needs to be taken one small step at a time and
digested slowly. In this chapter a series of programs will be presented, and then
in the last section of the chapter an OOP definition will be presented.

It is possible to start by explaining why OOP exists. In the early computer


science days there was little direction and structure used by programmers.
Programmers pretty much did their own thing and frequently programs were
designed in such a chaotic manner that it was impossible for large programs to be
altered, or updated at a later date. Order came to the computer science world with
modular and structured programming. This modular, structured approach is what
you have been practicing for some time now.

In the eighties, and very much in the nineties, software became more and more
sophisticated. Consumers demanded more, faster, prettier, and constantly better
software. The complexity of software was difficult to manage with the traditional
approach of designing a program. A new approach was necessary to make
programs more robust, more manageable and certainly easier to alter.

The solution to the new programming demands became programming with


objects. The ideas presented with this approach actually are not as radical as
many people think it is. There is a new set of vocabulary that scares some
students who are new to objects. The concepts, and the syntax of OOP is very

Chapter XVII Introduction to Object Oriented Programming 17.2


manageable and C++ is a very pleasant programming language to learn this
exciting style of programming.

Why Object Oriented Programming?

Object Oriented Programming is not so much a new approach


to programming, as it is a better implementation of the way
we have been programming.

Personally, I was confused for some time about this OOP business. I kept looking
for the difference and I did not find it. Sure there were many new, and powerful
features, but I did not see the dramatic change and difference that I expected.

Consider the following car analogy. Now a car is basically transportation. One
day somebody tells you that they have revolutionized transportation. You are
invited over and you see a nice looking car. This new car runs on water. It does
not pollute. It does not require an expensive source of fuel. Suddenly you have a
car that solves both the pollution problem and the energy problem. This is
terrific. But is this a new style of transportation? It is still a car with wheels,
doors and a steering wheel. It just happens to be a much better implementation of
the old type of car.

I personally maintain that a person, programmer, student, anybody who has been
creating programs according to well-established modular programming
techniques will embrace OOP. At the same time, they will not be doing anything
that is so radically different. They will be doing their old jobs better. Their
programs will be more reliable. The programs will be easier to update and it will
be easier to reach new levels of program complexity. In other words, your
programs will not pollute anymore and guzzle a lot of fuel, but it still is very
much a program.

This introduction is becoming tiresome. Teachers and students with prior OOP
knowledge are saying yes, that makes sense. But, you, the student who is trying
to learn this stuff, feels not one lick closer in understanding anything about OOP.
Basically, the time has come for... Show me the objects!.

Chapter XVII Introduction to Object Oriented Programming 17.3


17.2 A New Look at struct

The record data structure is only one chapter old, and now we are taking a closer
look at how C++ uses struct. There is more to this not-so-humble data structure.
We will start by repeating a program from the end of the last chapter. This is a
program that takes record information and displays a mailing address and a phone
listing. The ShowData function that displayed everything has been removed. It
is neither necessary, nor very realistic. This chapter will show a series of
programs that all accomplish the same task. Each program does it differently, but
the input and output is the same story. It is not necessary to waste a bunch of
paper to show the same output time and again. Basically, the program asks a
bunch of information and then displays a mailing label and a phone listing. So
when future programs say it has the same output as PROG1701.CPP you will
know what the story is.

PROG1701.CPP OUTPUT and OUTPUT FOR MANY OTHER PROGRAMS

Enter First Name ===>> Carlton


Enter Last Name ===>> Gutschick
Enter Street ===>> 7009 Orleans Court
Enter City State Zip ===>> Kensington, Md. 20795
Enter Phone Number ===>> 987-6543

Carlton Gutschick
7009 Orleans Court
Kensington, Md. 20795

Gutschick Carlton 7009 Orleans Court ....... 987-6543

Do not look at program PROG1701.CPP too long, trying to detect something


new and insightful. It is not there. We are starting with this program and say all
right, this is the standard approach that we learned in the modular programming
world. A data structure is created and a group of functions are written that
perform some action on the information stored in the data structure. Each
function performs its own designated task. After all, modular programming
dictates that you have one task, one module.

With this program as a start, we will make very gradual changes, and slowly
bridge the gap to the object world. Do not worry, the bridge is sturdy. Just make
sure that you walk in a straight line, and do not look down.

Chapter XVII Introduction to Object Oriented Programming 17.4


// PROG1701.CPP
// This program uses three functions that access the
// Worker structure.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

struct Worker
{
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
};

void EnterData(Worker &Employee);


void MailAddress(Worker Employee);
void PhoneListing(Worker Employee);

void main()
{
clrscr();
Worker Employee;
EnterData(Employee);
MailAddress(Employee);
PhoneListing(Employee);
getch();
}

void EnterData(Worker &Employee)


{
cout << "Enter First Name ===>> ";
getline(cin,Employee.FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,Employee.LastName);
cout << "Enter Street ===>> ";
getline(cin,Employee.Street);
cout << "Enter City State Zip ===>> ";
getline(cin,Employee.CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Employee.Phone);
}

void MailAddress(Worker Employee)


{
cout << endl << endl;
cout << Employee.FirstName << " " << Employee.LastName << endl;
cout << Employee.Street << endl;
cout << Employee.CityStateZip << endl;
}

void PhoneListing(Worker Employee)


{
cout << endl << endl;
cout << Employee.LastName << " " << Employee.FirstName
<< " " << Employee.Street
<< " ......." << Employee.Phone << endl;
}

Chapter XVII Introduction to Object Oriented Programming 17.5


How about doing something really weird? Why not rewrite the exact same
program and now place every one of the three functions, which access the Worker
record, inside the struct declaration. The data is already there, so why not also
place the functions that act upon the data in the same place.

// PROG1702.CPP
// This program places the three functions that access
the Worker
// data type inside the Worker struct declaration.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

struct Worker
{
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;

void EnterData()
{
cout << "Enter First Name ===>> ";
getline(cin,FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,LastName);
cout << "Enter Street ===>> ";
getline(cin,Street);
cout << "Enter City State Zip ===>> ";
getline(cin,CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Phone);
}

void MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Street << endl;
cout << CityStateZip << endl;
}

void PhoneListing()
{

Chapter XVII Introduction to Object Oriented Programming 17.6


cout << endl << endl;
cout << LastName << " " << FirstName << " "
<< Street << " ......." << Phone << endl;
}
};

void main()
{
clrscr();
Worker Employee;
Employee.EnterData();
Employee.MailAddress();
Employee.PhoneListing();
getch();
}

PROG1702.CPP OUTPUT

Same as PROG1701.CPP

When you try to run the program you will find that it compiles, and it also gives
the exact same output as the earlier program with the functions outside the data
structure. Play along with me. This looks strange, but you have just started to
walk on the bridge. Do not turn around and do not look down. Just keep
marching steadily across the ravine.

I do have a confession to make. The functions were not moved inside the struct
declaration exactly as they appeared before. Several significant changes were
made to allow this different approach to work.

Let us start by looking at the main function. The old function call shown in the
last chapter, and the first program in this chapter, calls the function and provides a
parameter to pass the required data structure information.

Old Function Call Approach New Function Call Approach

EnterData(Employee); Employee.EnterData();

Chapter XVII Introduction to Object Oriented Programming 17.7


The new approach does not pass the Employee parameter. With the new
approach EnterData is treated like a field in the Employee record and the
function is called the way that data is accessed in a record. We have placed
functions inside a record, and C++ has no problem with that. Now we access the
functions in the exact same manner that data fields of a record are accessed.

After we have studied the difference in the function calls, we must now check the
manner in which the functions process the data. You have been told that the
programs produce the same result with both methods, but there is a difference in
the statement syntax.

Old Function New Function


Process Approach Process Approach

cout << Employee.Street << endl; cout << Street << endl;
cout << Employee.CityStateZip; cout << CityStateZip;

The old approach starts with the record identifier, Employee, followed by a
period and then uses the field identifier to specify what record component is being
processed. With the new approach there is a serious lack of any type of record
identifier in sight. Odd? Not at all, because you are inside the record. Why
bother stating where Street is located when you are standing on the street in
question. So, we now have a large, messy looking struct declaration with a pile of
functions shoved inside. This is progress? Did somebody mention readability as
a desirable quality in a program? You are right. This is not what we desire and it
is just one small step. What did you learn from this step?

Functions and struct

C++ allows a function to be placed inside a struct declaration.


The function is called with the same period type syntax as
any other field in the data structure.

This time let us clean up the mess and still hang on to the same principles.
Program PROG1703.CPP also creates a data structure with functions inside the
declaration. The difference is that now only the function prototypes are used.
This approach gives an instantly cleaner look to the data structure. The function
implementations are elsewhere, but the record still contains the functions as
fields, because of the prototypes. This program will be divided into two sections.
First we examine the Worker declaration, and then we look at the functions.

Chapter XVII Introduction to Object Oriented Programming 17.8


// PROG1703.CPP
// This program creates a worker data type with only
function
// prototypes placed in the type declaration.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

struct Worker
{
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
void EnterData();
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();
Worker Employee;
Employee.EnterData();
Employee.MailAddress();
Employee.PhoneListing();
getch();
}

The main function is identical to the previous main function. Each one of the
functions is called by using the record identifier, Worker. A period separates the
record identifier from the field identifier that follows and calls each one of the
appropriate functions.

In the struct syntax you see normal, conventional function prototypes. The
placement is unconventional because the prototypes are inside the data structure
declaration, but the syntax of the function prototypes is the same, as if they were
declared in the usual global location, above the main function.

Chapter XVII Introduction to Object Oriented Programming 17.9


void Worker::EnterData()
{
cout << "Enter First Name ===>> ";
getline(cin,FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,LastName);
cout << "Enter Street ===>> ";
getline(cin,Street);
cout << "Enter City State Zip ===>> ";
getline(cin,CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Phone);
}

void Worker::MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Street << endl;
cout << CityStateZip << endl;
}

void Worker::PhoneListing()
{
cout << endl << endl;
cout << LastName << " " << FirstName
<< " " << Street
<< " ......." << Phone << endl;
}

The function implementations are certainly different. The program statements in


the function body are identical to the previous program, but the function headings
are very different.

Consider the following. Normally, when a function prototype is used, the


prototype is located globally in the C++ program. Elsewhere, below the
prototype, the function implementation is placed. Both the prototype and the
function implementation are global.

Now we have a different situation. We do not want our functions to be global.


We want these special functions that access the data in the record to be part of the
record. We have already accomplished this by placing the whole function inside
the record. This worked, but it is messy and we lose a lot of readability. Using
function prototypes is a neat clean solution and the record now shows all its
fields, both data and functions, in a compact, readable format.

Chapter XVII Introduction to Object Oriented Programming 17.10


The problem comes with the function implementation. A normal global function
implementation will look for a corresponding global function prototype. What
needs to be done is an indicator that the functions are not global but belong to a
data structure. This belonging quality is accomplished with a combination of
using the struct identifier with a new operator ::

void Worker::MailAddress()

This kind of function heading makes the following statement: This is function
MailAddress, which is a member of the Worker type. The new operator :: is
called a scope resolution operator. The name is pretty exotic but it is logical.
You remember the concept of scope explained a few chapters back.

Scope indicates where an identifier is available, just like the jurisdiction analogy
of various law enforcement agencies we discussed. If scope is not clear, go back
to Chapter XIV. This new operator resolves the scope of the function identifier
that follows.

Scope Resolution Operator ::

The scope resolution operator is used in function headings


that are members of a previously declared record. It separates
the identifier of the struct data type from the identifier of the
function that is a member of the struct data type.

General syntax:
void struct-identifier::function-identifier

Example syntax:
void Worker::MailAddress()

Chapter XVII Introduction to Object Oriented Programming 17.11


The struct data structure is proving to be quite versatile. In the last chapter you
were introduced to this data structure as a data type with the ability to store
information of many different types. Now you find that it has the ability to not
only store data, but also store functions.

17.3 The First Object Definition

We are slowly creating special data types. Data types that are different from the
ones we have used before. You have been looking at the C++ data structure,
struct, which stores not only information in various fields, but also stores the
function information that accesses the data. A data type with such unique
capabilities has to be special and you are getting suspicious. Is this maybe an
object? Bingo, we have been sneaking some new data structure into your mind
and this new data structure is none other than your-soon-to-be-new-friend, the
object. It is now time for a first definition of this new and all-important computer
science feature.

A First Object Definition

An object is a data structure that contains both a variety


of data information and the functions that access and
process the data information.

At this early object stage you have not seen any new capability yet. It is nice
enough to place functions inside records, but nothing has been accomplished that
has not been done before. In the last chapter you could print mailing labels and
phone listing with our program. That program contained a record of information
and a variety of functions that processed the required data. In this chapter we are

Chapter XVII Introduction to Object Oriented Programming 17.12


accomplishing the exact same tasks, but now we place the functions inside the
record along with the data.

There is bunches more to learn about objects, but right now you need to be clear
on the first definition before you move on. Do note that this first definition is an
object definition and not object oriented programming. There is quite a
difference. It is easier to explain driving, after you have defined what a car is.

The next program example accomplishes the same old task once again, but it does
it very poorly. The EnterData function has been removed and information is
entered with program input statements in the main function. This is considered
bad programming style. The data in an object should be accessed indirectly with
a function, and not directly from anywhere in the program.

// PROG1704.CPP
// This program has removed the EnterData function and enters
// all Employee information in the main function.
// This is an example of very poor program design.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

struct Worker
{
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();
Worker Employee;

cout << "Enter First Name ===>> ";


getline(cin,Employee.FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,Employee.LastName);
cout << "Enter Street ===>> ";
getline(cin,Employee.Street);
cout << "Enter City State Zip ===>> ";
getline(cin,Employee.CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Employee.Phone);

Employee.MailAddress();
Employee.PhoneListing();

Chapter XVII Introduction to Object Oriented Programming 17.13


getch();
}

void Worker::MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Street << endl;
cout << CityStateZip << endl;
}

void Worker::PhoneListing()
{
cout << endl << endl;
cout << LastName << " " << FirstName
<< " " << Street
<< " ......." << Phone << endl;
}

There is nothing preventing a programmer from accessing information like Street


and Phone directly in the main function. It only takes two identifiers. First an
identifier for the data structure, which is Employee. This is followed by a period
and a second identifier for the field in the record, which may be Street.

You know that this type of C++ syntax works. You just learned it in the last
chapter. So what is wrong and why must we use functions to access data in an
object? The reasoning for this is connected with the reason why objects exist in
the first place. The biggest challenge of any program is to make the program
work correctly, for all situations. That is a tall order and many programs,
including sophisticated professional software, fall short when the real world uses
the software in many different applications.

One reasons for this software problem is that program users do so many
unexpected things, and frankly, programmers can be pretty quirky too and display
some serious cerebral lapses. The intent with objects is to create data structures
that look after themselves. If we create a neat package of data and functions, it
becomes easier to make sure that the data is processed properly. For example, a
loop that displays data information may cause problems if the data is not present.
It is quite possible that some programmer who accesses the data directly is not
aware of a situation where some database of information is empty. On the other
hand, a local function inside the object, can be written to carefully check different
situations. Such a function only displays data when it is proper to do so without
any computer problems.

You are pleased and I am pleased that the functions inside an object do such a
good job protecting the objects data from harm. But what prevents intentional or
unintentional bad programming that goes ahead and accesses data directly

Chapter XVII Introduction to Object Oriented Programming 17.14


anyway. You know, it is a fact that not everybody listens to good advice,
especially people who need the advice.

C++ has a nice feature that adds discipline to our objects. It is possible to indicate
segments of the data structure as private and other segments as public. Any
identifier placed in the private segment is only accessible by the object itself.
Outside program statements cannot access any of the private identifiers. Program
PROG1705.CPP demonstrates the proper syntax for the reserved words private
and public in a struct declaration.

The order is not significant. You may select to start with the private segment, or
the public segment. People have various reasons why they select one approach or
the other. The C++ compiler does not care.

// PROG1705.CPP
// This program adds private and public segments to the Worker
// data structure. It is no longer possible to access data
// fields from the main function, which in compile errors.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

struct Worker
{
private:
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
public:
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();
Worker Employee;
cout << "Enter First Name ===>> ";
getline(cin,Employee.FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,Employee.LastName);
cout << "Enter Street ===>> ";
getline(cin,Employee.Street);
cout << "Enter City State Zip ===>> ";
getline(cin,Employee.CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Employee.Phone);
Employee.MailAddress();
Employee.PhoneListing();

Chapter XVII Introduction to Object Oriented Programming 17.15


getch();
}

void Worker::MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Street << endl;
cout << CityStateZip << endl;
}

void Worker::PhoneListing()
{
cout << endl << endl;
cout << LastName << " " << FirstName << " "
<< Street << " ......." << Phone << endl;
}

Program PROG1705.CPP does not compile. Data is accessed exactly as it was


done previously in the main function. This time the inclusion of the little word
private: prevents public access. Your compiler will give an error like:

PROG1705.CPP OUTPUT

Compiling PROG1705.CPP:
Error PROG1705.CPP 31: ’Worker::FirstName’ is not
accessible
Error PROG1705.CPP 33: ’Worker::FirstName’ is not
accessible
Error PROG1705.CPP 35: ’Worker::FirstName’ is not
accessible

Ironically, we were doing fine in the beginning of this chapter when we used an
EnterData function. We will return to that approach and our program compiles
nicely, even with private and public added inside the Worker record. The next
program demonstrates the proper way to access private data. Program
PROG1706.CPP provides proper protection of the Worker data information.

// PROG1706.CPP
// This program demonstrate the correct way use the data in
// Worker by using only accessing functions.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H

Chapter XVII Introduction to Object Oriented Programming 17.16


struct Worker
{
private:
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
public:
void EnterData();
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();
Worker Employee;
Employee.EnterData();
Employee.MailAddress();
Employee.PhoneListing();
getch();
}

void Worker::EnterData()
{
cout << "Enter First Name ===>> ";
getline(cin,FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,LastName);
cout << "Enter Street ===>> ";
getline(cin,Street);
cout << "Enter City State Zip ===>> ";
getline(cin,CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Phone);
}

void Worker::MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Street << endl;
cout << CityStateZip << endl;
}

void Worker::PhoneListing()
{
cout << endl << endl;
cout << LastName << " " << FirstName << " "
<< Street << " ......." << Phone << endl;
}

17.4 From struct to class

Chapter XVII Introduction to Object Oriented Programming 17.17


Did you know that struct does not have a monopoly on creating objects. There is
another - and better - way to get to this object business. We can use the C++
reserved word class in place of struct and you will notice everything working just
fine. Program PROG1707.CPP is a rehash of the same tired program that you
have stared at for far too many pages. There is one significant change. In the
place of struct is now the word class.

The whole program will not be shown here. Rest assured that the program
compiles and works. Besides, all you need to do is take the previous program and
substitute struct with class.

// PROG1707.CPP
// This program is almost identical to the previous
program.
// The only difference is that the Worker type is now
implemented
// with the reserved word class in place of struct.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

class Worker
{
private:
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
public:
void EnterData();
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();

Chapter XVII Introduction to Object Oriented Programming 17.18


Worker Employee;
Employee.EnterData();
Employee.MailAddress();
Employee.PhoneListing();
getch();
}

Logical, pondering students have a basic question here. Objects with struct were
doing just dandy. Data and functions were sitting nice and cozy inside the record
and the job was accomplished. Now you are told that we can do the same job
with class. Fine, but why? What does class have that struct lacks?

The answer to the why-class question will be partially answered by looking at the
next program example. Program PROG1708.CPP has great similarities to the
previous program. There is only one small change. The reserved words private
and public have been removed from the Worker data type declaration. Try this
program and watch what happens.

// PROG1708.CPP
// This program demonstrates that in a class
declaration
// all fields are defaulted to private.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

class Worker
{
apstring FirstName;
apstring LastName;
apstring Street;
apstring CityStateZip;
apstring Phone;
void EnterData();
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();
Worker Employee;
Employee.EnterData();

Chapter XVII Introduction to Object Oriented Programming 17.19


Employee.MailAddress();
Employee.PhoneListing();
getch();
}

void Worker::EnterData()
{
cout << "Enter First Name ===>> ";
getline(cin,FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,LastName);
cout << "Enter Street ===>> ";
getline(cin,Street);
cout << "Enter City State Zip ===>> ";
getline(cin,CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Phone);
}

void Worker::MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Street << endl;
cout << CityStateZip << endl;
}

void Worker::PhoneListing()
{
cout << endl << endl;
cout << LastName << " " << FirstName << " "
<< Street << " ......." << Phone << endl;
}

PROG1708.CPP OUTPUT

Compiling PROG1708.CPP:
Error PROG1708.CPP 29: ’Worker::EnterData()’ is not
accessible
Error PROG1708.CPP 30: ’Worker::MailAddress()’ is not
accessible
Error PROG1708.CPP 31: ’Worker::PhoneListing()’ is not
accessible

Chapter XVII Introduction to Object Oriented Programming 17.20


The program does not compile and error messages appear, indicating that the
three functions inside the Worker type are not accessible. This is very strange.
You know for a fact that several programs ago, before you knew that private and
public existed, the programs worked just fine. You can check out this little fact
by doing another quick substitution, placing struct where class is. The program
will then work without difficulty.

Understanding what is happening requires a little lesson in program language


history. The language C, originally developed for the UNIX operating system,
became surprisingly popular. Programmers worldwide liked its flexibility, power
and easy access to low level routines. C became the professional programmer’s
choice in a surprisingly short period of time. Earlier in the chapter there was a
section explaining that Object Oriented Programming was developed when a
greater emphasis was placed on programs that are more reliable and are easier to
update. Accomplishing this task with increasingly complex programs became
more and more difficult, which motivated the development of Object Oriented
Programming.

Several languages were developed with OOP capability. Bjarne Strousop created
a new language based on C with two major improvements. He wanted to
eliminate some of C’s quirkier features and also add OOP. His original choice for
the new language was C Plus Classes. Classes in this case implies OOP
capability. Hang on just a little bit and the world class will make more sense.
Right now it is sufficient to regard class the same as an object.
The widespread use and popularity of C made it impossible to ignore. A new
language based on C, yet an improvement on C, needed to be backwardly
compatible. This meant that the new language was capable of compiling and
running any of the older programs. Without this backward compatibility,
commercial success of the new language would be doubtful.

This explains why today all the C features are alive and well in C++. Many of the
quirkier features have not been taught, but they exist. This brings us to the
manner of implementing objects. The existing struct was a natural choice for
storing data and functions. Old C programs already used struct for data only.
This capability had to be preserved for backward compatibility reasons.

Bjarne Strousop also wanted objects to be implemented correctly, forcing


programmers to use private and public segments so that data would be accessed
only by object functions. He created the class as a data structure that defaults
every element in the data structure to private. In other words, unless you make
something public, it will automatically be private and inaccessible. This forces
programmers to act to access data. With struct, you can achieve the same result,

Chapter XVII Introduction to Object Oriented Programming 17.21


but the default with struct is that all data is public. A programmer might forget,
and the result is an object that is not as reliable.

Why not simply make all the information in struct private? Why bother with two
separate reserved words that almost do the same thing? Backward compatibility
once again. If struct had been changed to default all its members to private, old
C-style programs would not work properly. Data would not be accessible because
C programs do not use private and public segment inside struct.

Struct and Class

C++ struct creates a record data structure, such that


all its elements default to public.

C++ class creates a record data structure, such that


all its elements default to private.

17.5 Classes and Objects

We need to stop and take some inventory of some confusing vocabulary that is
being tossed around. We have records that are implemented with struct and
class. We also seem to have objects that are implemented with struct and class.
Furthermore, we talk about objects and we talk about classes. This is a time-out
section. We need to catch our breath and look around. The end of the last section
stated that information stored in a record implemented with struct defaults to
public. The same record information implemented with class defaults to private.
At the C++ program code level that seems to make sense.

Now we need to move on and tackle the object and class business. The
distinction is surprisingly simple. A class is a data type and an object is a
variable. Look at the main function below from the latest program. In this main
function the identifier Worker is the Class and the identifier Employee is the
object.

Chapter XVII Introduction to Object Oriented Programming 17.22


void main()
{
clrscr();
Worker Employee;
Employee.EnterData();
Employee.MailAddress();
Employee.PhoneListing();
getch();
}

Objects and Classes Distinction

A class is a data type.

An object is a variable.

This distinction should not be confusing. You have for many weeks, and for
many chapters been aware of the difference between a type and a variable. The
only reason why there tends to be a confusion at this stage is because the type is
created by the programmer and it is not already available in C++.

The program statement

int Number;

causes few problems. int is the data type, and Number is the variable. Now we
can also create our own type with typedef and have the following kind of
program statements.

typedef int Integer;


Integer Number;

In this example Integer is now a data type and Number is the variable. When we
increase the complexity by creating our own data structure with either struct or
class, we still have a data type.

Chapter XVII Introduction to Object Oriented Programming 17.23


At the instance that a variable is defined, an object is created or constructed. If
our class is called Worker, the proper terminology is to say that Employee is an
instance of the class Worker. Consider an analogy with a cat. Nobody pets or
feeds cat. You pet or feed Fluffy, which is one instance of a cat.

So we have this class and object difference pretty straight. Part of the confusion
is that objects and Object Oriented Programming, as well as classes are talked
about in a generic sense. Technically speaking Kleenex is one brand (or instance)
of tissue, but we often talk about needing a Kleenex, even when the tissue brand
might be totally different.

But are you straight on struct and class? You know the default difference, but do
you realize that both struct and class create a CLASS. Yes that is right. The C+
+ reserved word class can be used to declare a class, and the C++ reserved word
struct can also be used to declare a class. If you think back to the previous
sample programs, you observed the evidence that struct and class both created
records that contained data and functions.

Once again this dual-class-creation possibility is not for the purpose of confusing
new computer science students. It is all part of the backward compatibility
emphasis. Furthermore, you will find that we can suggest a convenient way to
use both data structures in our C++ programs.

APCS Examination Alert

The APCS Committee advises students to use class for


all situations where the intention is to create a new class.

The APCS Committee recommends that struct is used


for record data structures that do not contain functions and
will not be used as objects.

Technically, a data structure created with struct is a CLASS.


However, if the data is not protected with private and the
data is accessed directly then the data type will be used
and treated like a NON-OOP record data structure,
and not a CLASS.

Chapter XVII Introduction to Object Oriented Programming 17.24


One last look at the tired Employee program will help to clarify this struct and
class business. Program PROG1709.CPP produces the exact same output as all
the previous programs. The only difference is with the type declarations. First,
focus on the declarations of Location and Worker.

struct Location
{
apstring Street;
apstring CityStateZip;
};

class Worker
{
private:
apstring FirstName;
apstring LastName;
Location Address;
apstring Phone;
public:
void EnterData();
void MailAddress();
void PhoneListing();
};

Note, that a special Location type is declared to store information about a


person’s address. True, it is not necessary to do this, but play along. You decide
to store this information in a record. Furthermore, assume that your intention is to
use this newly created type inside another record, which will become a class. The
point is this: The Location type has no functions inside it. It does not have
private or public segments. Everything defaults to public. In other words, for all
practical purposes this technically-speaking class is not really meant to be a class,
and you do not need to treat it as such. Now since our intentions is not to use
Location as a class, we use the C++ reserved word struct. Later in the
declaration, the Worker type is very much meant to be a class. You see that
functions are included and the data structure has a private and public segment.
In this situation we use C++ reserved word class.

The complete program follows to make sure that you realize the necessary
changes that have to be made. The nested Location type alters the required
syntax in the way you learned about nested records in the last chapter. It is not

Chapter XVII Introduction to Object Oriented Programming 17.25


necessary to specify Employee, but you do need to say Address because the
fields Street and CityStateZip are not local to the Worker class.

// PROG1709.CPP
// This program uses one record, implemented with
struct,
// used by another data structure, implemented with
class.

#include <iostream.h>
#include <conio.h>
#include "APSTRING.H"

struct Location
{
apstring Street;
apstring CityStateZip;
};

class Worker
{
private:
apstring FirstName;
apstring LastName;
Location Address;
apstring Phone;
public:
void EnterData();
void MailAddress();
void PhoneListing();
};

void main()
{
clrscr();
Worker Employee;
Employee.EnterData();
Employee.MailAddress();
Employee.PhoneListing();

Chapter XVII Introduction to Object Oriented Programming 17.26


getch();
}

void Worker::EnterData()
{
cout << "Enter First Name ===>> ";
getline(cin,FirstName);
cout << "Enter Last Name ===>> ";
getline(cin,LastName);
cout << "Enter Street ===>> ";
getline(cin,Address.Street);
cout << "Enter City State Zip ===>> ";
getline(cin,Address.CityStateZip);
cout << "Enter Phone Number ===>> ";
getline(cin,Phone);
}

void Worker::MailAddress()
{
cout << endl << endl;
cout << FirstName << " " << LastName << endl;
cout << Address.Street << endl;
cout << Address.CityStateZip << endl;
}

void Worker::PhoneListing()
{
cout << endl << endl;
cout << LastName << " " << FirstName << " "
<< Address.Street << " ......." << Phone << endl;
}

Chapter XVII Introduction to Object Oriented Programming 17.27


17.6 The Step-By-Step Class

I know exactly what is needed right now. Simplicity, not complexity. This
section will not throw a series of complex programs at you. Rather, we will
examine some extremely short, simple programs and along the way learn some
new OOP concepts.

Everything in this chapter has been designed to introduce you to programming


with objects. Hopefully, you have understood the program examples. But can
you create a program yourself that uses objects? In this section, I will use a
different approach. Together we are going to create a program that starts at the
minimal level and slowly add pieces to the growing program. Each new piece
will be explained.

You will get the best value from this section if you sit behind a computer and type
in each program. There will be ten stages. Each stage is not a new start. Some
small addition will need to be made to the growing program. There is a benefit in
typing each one of these stages on your computer. The slowness of the typing is
precisely what the doctor (or your teacher) ordered. You see the program
unfolding in front of your eyes and concepts sink in more clearly and thoroughly
at that speed.

Stage #1, The Minimal Class Program

Program DECK01.CPP could not be simpler. The program displays nothing, but
it does compile and gets us started with the minimal program statements for a
program with a user-created class.

// DECK01.CPP
// Stage #1 is the minimal class program that compiles.

class CardDeck
{
};

void main()
{
}

Chapter XVII Introduction to Object Oriented Programming 17.28


Stage #2, Adding Private and Public Segments

In Stage #2, the reserved words private and public are added. Right now these
words are meaningless since there is not anything that can be private or public.
The intention here is to create good habits. One good habit is to start with a
skeleton that alerts you to using private and public segments. This stage also
creates a little output, which makes the program more practical to execute.
Another important step in this program to observe is that we now have an object.
Note that identifier D is the object, and CardDeck is the class. The program
statement . . . . CardDeck D; . . . . is the instantiation of the object D.

// DECK02.CPP
// Stage #2 is more practical. It is still a minimal
// skeleton program, but it does have some output.
// This program "instantiates" an object D of the
CardDeck class.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:

public:

};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #2" << endl;
CardDeck D;
getch();
}

Stage #3, Adding Private Members

Chapter XVII Introduction to Object Oriented Programming 17.29


In stage #3 we think about the data that needs to be stored in our CardDeck class.
A decision is made to store the number of decks in NumDecks, the number of
card players in NumPlayers, the number of cards dealt to each player in
CardsDealt, and the number of cards left in the deck(s) in CardsLeft. I am sure
that we can easily create additional variables that store useful information, but for
now this will be sufficient. Our mission is to learn about OOP, not about cards.
There is a popular OOP name for the four identifiers we have placed in our
CardDeck class. The data fields that store class information are called the
attributes of the class.

// DECK03.CPP
// Stage #3 adds the private data members to the class.
// These are the attributes of the CardDeck class.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #3" << endl;
CardDeck D;
getch();
}

Stage #4, Adding a Constructor

Do not be surprised if constructor does not ring a bell at all. This is a totally new
concept that was not shown with any of the previous programs. Students familiar
with OOP may even have wondered about the omission of such an important class

Chapter XVII Introduction to Object Oriented Programming 17.30


component as the constructor. Well, this was intentional. You know that I feel
strongly about feeding information with small bites. If the bite is too big, you
chew forever and the food still does not go down.

Objects were meant to make programs more reliable. One common program
problem in times past, was that programs would crash because various data
structures had not receive the proper information. In many cases such crashes
could have been prevented if the data structure information was properly
initialized. It is the job of the constructor to properly initialize the object during
its instantiation. You can also say during the construction of the object. The
constructor is a special public function of a class, and the constructor function is
automatically called in the program statement that defines the object. In other
words, at the instantiation of the object, the constructor function is called and the
object is initialized. We need to look at two locations to understand this
constructor business. There is the constructor in the class declaration, and there is
the implementation of the constructor.

// DECK04.CPP
// Stage #4 adds a simple constructor function.
// The purpose of the constructor is to initialize the
class.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck(); // constructor
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #4" << endl;
CardDeck D;
}

CardDeck::CardDeck() // constructor
{
cout << endl << endl;

Chapter XVII Introduction to Object Oriented Programming 17.31


cout << "CONSTRUCTOR CALL" << endl;
NumDecks = 1;
NumPlayers = 1;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
getch();
}

It is easy to identify the constructor in the class. The function heading of the
constructor is the name of the class itself without void and also without a return
type. Traditionally, the constructor is the first member function placed in the
public segment. The constructor must be in the public segment of the class.
The implementation of the constructor member function is also a little unusual.
Both the class identifier is CardDeck and the field identifier is CardDeck. This
says that the function CardDeck is located in the CardDeck class. This is all a
little weird, but it has to do with reliability and initialization. Using the class
name for this special member function means that the function will be
automatically called during the instantiation of the new object. You see, it is not
good enough to create a function that initializes an object. You have to make sure
that the function is called. Giving the function the same name as the class itself is
the way that C++ guarantees that the constructor function will be called.

The constructor in the CardDeck class includes the statement CONSTRUCTOR


CALL. This is not a common habit in a constructor. It is useful in this
demonstration program because it shows you when the constructor is called. Go
ahead and run the program. When exactly is the constructor function called?

You will also note that the initialization in the constructor function makes certain
assumptions. It is assumed that every card game in the program requires at least
one deck, every game has at least one player, there will be 52 cards in a deck and
at least one card is dealt for each hand. Most card games may require different
values. That is fine and such games can create appropriate functions to alter the
necessary values. For the sake of initialization the selection above is satisfactory.

Constructor Definition

A constructor is a special public class member function


that is called during the instantiation of a new object.

The purpose of the constructor is to initialize the new object


with values, allocate necessary memory, and handle other
requirements for the reliable use of the new object.

Chapter XVII Introduction to Object Oriented Programming 17.32


The constructor has the same name as the class.

The constructor is a function which has neither a return


type nor a void.

Stage #5, Adding a ShowData Member Function

It is time to add a member function to the class that does something. All the data
in the CardDeck class is private and cannot be accessed directly. We need a
member function that can access the data and show us the contents. Class
member functions are also called actions or methods. Think of attributes as
nouns and actions as verbs. Right now the only action we are interested in is
showing the value of each one of the attributes (or data members) in the
CardDeck class. This is done in a manner that you have seen in previous
programs.

// DECK05.CPP
// Stage #5 adds a public member function to display
the
// private data.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck();
void ShowData();
};

Chapter XVII Introduction to Object Oriented Programming 17.33


void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #5" << endl;
CardDeck D;
D.ShowData();
}

CardDeck::CardDeck()
{
cout << endl << endl;
cout << "CONSTRUCTOR CALL" << endl;
NumDecks = 1;
NumPlayers = 1;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
getch();
}

void CardDeck::ShowData()
{
cout << endl << endl;
cout << "SHOW DATA FUNCTION" << endl;
cout << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
cout << "CardsLeft: " << CardsLeft << endl;
cout << "CardsDealt: " << CardsDealt << endl;
getch();
}

Stage #6, Adding a Destructor

This stage adds yet another special class feature called the destructor. This is
another public member function that is called automatically. This time the
function is not called when the object is created, but rather when the object is no
longer used by the program. There is a time when the object is destroyed. At that
time the special destructor function is called.

Why is this necessary? Think of the destructor as a house keeping function.


Your nifty object may have special memory requirements or use other special
computer resources that need to be put back in order. Perhaps a good example
comes from graphics. The constructor function can be used to put the computer

Chapter XVII Introduction to Object Oriented Programming 17.34


output in graphics mode and the destructor returns the computer to regular text
mode. Frankly, there is not much we can do with the CardDeck class that
requires cleaning up afterwards. For now the destructor function will only
generate a message stating that the function has been called.

In later chapters there will be programs that use computer memory in a special
way. Such programs require special memory management and cleaning up tasks
for which the destructor is ideally suited. At this stage, it is important to realize
that the destructor exists.

The syntax of the destructor is very similar to the constructor. The name of the
class is the name of the destructor with a tilde ( ~ ) in front of the identifier.
Typically the destructor is placed directly below the constructor in the public
segment of the class.

Run the program, with the new destructor function added and determine exactly
where the destructor does its job. The output message of the destructor function
should give you the desired information.

// DECK06.CPP
// Stage #6 adds a destructor function.
// The purpose of the destructor is to de-initialize
the
// creation of the CardDeck object.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck();
~CardDeck();

Chapter XVII Introduction to Object Oriented Programming 17.35


void ShowData();
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #5" << endl;
CardDeck D;
D.ShowData();
}

CardDeck::CardDeck()
{
cout << endl << endl;
cout << "CONSTRUCTOR CALL" << endl;
NumDecks = 1;
NumPlayers = 1;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
getch();
}

CardDeck::~CardDeck()
{
cout << endl << endl;
cout << "DESTRUCTOR CALL" << endl;
getch();
}

void CardDeck::ShowData()
{
cout << endl << endl;
cout << "SHOW DATA FUNCTION" << endl;
cout << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
cout << "CardsLeft: " << CardsLeft << endl;
cout << "CardsDealt: " << CardsDealt << endl;
getch();
}

Chapter XVII Introduction to Object Oriented Programming 17.36


Destructor Definition

A destructor is a special public class member function


that is called during the destruction of an object.

The purpose of the destructor is to clean up any potential


problems caused by the existence of the object. In many
cases this means that memory used by the object is
returned for further use by the program.

The destructor has the same name as the class and is


preceded by a tilde ( ~ )

The destructor is a function which has neither a return


type nor a void.

There can only be one destructor function.

Stage #7, Adding Functionality to the Class

The ShowData member function helps in demonstrating the proper syntax of


functions that are members of a class. It is not really a good example of how
member functions handle the member data. Put in other words, it is not a good
example of how the actions or methods of a class access the attributes of a class.

So what exactly does one do with a card deck? Decks are shuffled, they are dealt,
they are cut, and used in numerous different actions that are demanded by various
different card games.

Right now we will keep it simple. Our small little class will be given the
opportunity to Shuffle the deck, Deal the cards and determine how many cards
are Left. Functions ShuffleCards and DealHand are void functions. Function
CheckCardsLeft returns an integer. This stage only adds the prototypes in the
CardDeck class. The program is not shown in its entirety.

Chapter XVII Introduction to Object Oriented Programming 17.37


// DECK07.CPP
// Stage #7 adds the prototypes of the new member
functions,
// ShuffleCards, DealHand and CheckCardsLeft.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck();
~CardDeck();
void ShowData();
void ShuffleCards();
void DealHand();
int CheckCardsLeft();
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #7" << endl;
CardDeck D;
D.ShowData();
}

Stage #8, Implementing the Member Functions

Stage #8 implements the newly selected class actions, method, member functions,
whatever. Nothing new is shown. We now start to have a fairly complete
program. Many students may be surprised by the implementation of the members
functions. A quick peek at the ShuffleCards function shows little evidence of a
function that shuffles much of anything, let alone itself.

Chapter XVII Introduction to Object Oriented Programming 17.38


Please understand this point very clearly. The program code that shuffles a deck
of cards has absolutely nothing to do with learning Object Oriented Programming
concepts. I had difficulty learning OOP initially because I found so much
unrelated programming code surrounding the meat-and-potatoes OOP syntax that
I was looking for. Essentially, we are saying that the job of the ShuffleCards
functions is to state that the cards are shuffled. Function CheckCardsLeft is
more important. It accesses private data members and processes information.

// DECK08.CPP
// Stage #8 implements the new member functions,
// ShuffleCards, DealHand and CheckCardsLeft.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck();
~CardDeck();
void ShowData();
void ShuffleCards();
void DealHand();
int CheckCardsLeft();
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #7" << endl;
CardDeck D;
D.ShowData();
D.ShuffleCards();
D.DealHand();
cout << "There are " << D.CheckCardsLeft()
<< " cards left in the deck " << endl;
}

Chapter XVII Introduction to Object Oriented Programming 17.39


CardDeck::CardDeck()
{
cout << endl << endl;
cout << "CONSTRUCTOR CALL" << endl;
NumDecks = 1;
NumPlayers = 1;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
getch();
}

CardDeck::~CardDeck()
{
cout << endl << endl;
cout << "DESTRUCTOR CALL" << endl;
getch();
}

void CardDeck::ShowData()
{
cout << endl << endl;
cout << "SHOW DATA FUNCTION" << endl;
cout << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
cout << "CardsLeft: " << CardsLeft << endl;
cout << "CardsDealt: " << CardsDealt << endl;
getch();
}

void CardDeck::ShuffleCards()
{
cout << endl << endl;
cout << "SHUFFLE CARDS FUNCTION" << endl;
getch();
}

void CardDeck::DealHand()
{
cout << endl << endl;
cout << "DEAL HAND FUNCTION" << endl;

Chapter XVII Introduction to Object Oriented Programming 17.40


getch();
}

int CardDeck::CheckCardsLeft()
{
cout << endl << endl;
cout << "CHECK CARDS LEFT FUNCTION" << endl;
getch();
return CardsLeft;
}

Stage #9, Improving the Constructor

This stage is designed to show that constructors can have more versatility than
initialize class member data. It will demonstrate that a member function is
perfectly capable of calling another member function in the class. In the case of a
constructor this can have practical benefits. The improved constructor in this
program is not real clever, but it shows an important feature. Our CardDeck
class includes a ShuffleCards function. Shuffling is a practical feature for any
card game, but should the cards not be shuffled before any game even starts. This
is precisely what should be done by the constructor. The job of the constructor is
to set the proper stage. This includes not only initializing variables with some
values, but also calling appropriate functions, like ShuffleCards. Stage #9 will
just show a partial program to focus on the small change in the constructor.
// DECK09.CPP
// Stage #9 uses an improved constructor.
// In this program the constructor not only initializes
the data
// members, but also calls the ShuffleCards function to
insure
// that cards will be shuffled for any new object.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;

Chapter XVII Introduction to Object Oriented Programming 17.41


int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck();
~CardDeck();
void ShowData();
void ShuffleCards();
void DealHand();
int CheckCardsLeft();
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #9" << endl;
CardDeck D;
D.ShowData();
D.ShuffleCards();
D.DealHand();
cout << "There are " << D.CheckCardsLeft()
<< " cards left in the deck " << endl;
}

CardDeck::CardDeck()
{
cout << endl << endl;
cout << "CONSTRUCTOR CALL" << endl;
NumDecks = 1;
NumPlayers = 1;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
ShuffleCards();
getch();
}

Stage #10, Adding a Second Constructor

Chapter XVII Introduction to Object Oriented Programming 17.42


The constructor shown earlier is the default constructor. Even with the
improvement of the last program, it is still your plain, vanilla default constructor.
This constructor initializes the new object according to the default specifications.
C++ knows that that the default constructor should be called because the
instantiation of the new object is done without any parameters. A statement like:

CardDeck D;

creates a new object D, and D has no parameters at all. Translation ..... call the
default constructor. C++ knows which constructor is the default constructor
because the constructor name is used in the function heading without any
parameters. This paragraph gives you a strong feeling that other constructors are
lurking around the corner. You are totally correct. After all, would it not be nice
to have a little say-so about the manner in which your objects are initialized.

Two, three chapters ago you learned about functions. One of the last function
features you learned was about overloading functions. You learned that the
same function name could be used with a variety of different function
implementations. C++ would sort out the details by matching up the appropriate
parameters and then decide which function to call.

Adding a second constructor means that we will overload the constructor. This is
no problem, as long as we give C++ a clear indication of our intentions. The
second constructor needs some parameters to help distinguish it from the first
constructor. Why do we need a second constructor? How about indicating how
many people are playing, and how card decks should be shuffled. This is
practical stuff and it would be nice if we could control that.

Program DECK10.CPP instantiates (does this term make sense now?) two
objects. The first object, D1, calls the default constructor. Notice there are no
parameters anywhere near D1. Same old constructor, nothing fancy. The second
object, D2, includes two parameters, D2(4,5). The 4 is passed to the number of
decks variable, and the 5 is passed to the number of players variable.

The second - overloaded - constructor intentionally displays the number of


initialized decks, and the number of players to help you distinguish between the
two constructors. This shows another good application for overloaded functions.
There is more to life than swapping plain data. Run program DECK10.CPP, and
check the output. You will note a variety of interesting results. The output is
intentionally not shown. In how many ways is this program different? Only your
computer and your teacher know for sure. Remember this was meant to be a
hands-on section. So get your hands on, if they have been idle.
// DECK10.CPP
// Stage #10 adds a second constructor that initializes
NumDecks
// and NumPlayers to a specified value. The original,

Chapter XVII Introduction to Object Oriented Programming 17.43


// parameterless constructor is called the "default"
constructor.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
int CardsLeft;
int CardsDealt;
public:
CardDeck();
CardDeck(int,int);
~CardDeck();
void ShowData();
void ShuffleCards();
void DealHand();
int CheckCardsLeft();
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #10" << endl;
CardDeck D1;
D1.ShowData();
D1.ShuffleCards();
D1.DealHand();
cout << "There are " << D1.CheckCardsLeft()
<< " cards left in the deck " << endl;
CardDeck D2(4,5);
D2.ShowData();
D2.ShuffleCards();
D2.DealHand();
cout << "There are " << D2.CheckCardsLeft()
<< " cards left in the deck " << endl;
}

CardDeck::CardDeck()
{

Chapter XVII Introduction to Object Oriented Programming 17.44


cout << endl << endl;
cout << "CONSTRUCTOR CALL" << endl;
NumDecks = 1;
NumPlayers = 1;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
ShuffleCards();
}

CardDeck::CardDeck(int ND, int NP)


{
cout << endl << endl;
cout << "SECOND CONSTRUCTOR CALL" << endl;
NumDecks = ND;
NumPlayers = NP;
cout << NumDecks << " card decks will be shuffled
for "
<< NumPlayers << " players" << endl;
CardsLeft = NumDecks * 52;
CardsDealt = 1;
ShuffleCards();
}

CardDeck::~CardDeck()
{
cout << endl << endl;
cout << "DESTRUCTOR CALL" << endl;
getch();
}

void CardDeck::ShowData()
{
cout << endl << endl;
cout << "SHOW DATA FUNCTION" << endl;
cout << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
cout << "CardsLeft: " << CardsLeft << endl;
cout << "CardsDealt: " << CardsDealt << endl;
getch();
}

Chapter XVII Introduction to Object Oriented Programming 17.45


void CardDeck::ShuffleCards()
{
cout << endl << endl;
cout << "SHUFFLE CARDS FUNCTION" << endl;
getch();
}

void CardDeck::DealHand()
{
cout << endl << endl;
cout << "DEAL HAND FUNCTION" << endl;
getch();
}

int CardDeck::CheckCardsLeft()
{
cout << endl << endl;
cout << "CHECK CARDS LEFT FUNCTION" << endl;
getch();
return CardsLeft;
}

17.7 Declaring const Functions

At various intervals I mentioned that one major goal of object oriented


programming is program reliability. Packaging both the data and the functions
that act on the data in the same data type increases reliability. Reliability is
further increased by placing data in the private segment of the class declaration.
This packaging process is one major corner stone of object oriented programming,
which is called encapsulation.

Encapsulation Notes:

Encapsulation is the process of placing a data structure’s


data (attributes) with the functions (actions) that act upon
the data inside the same data structure.

Encapsulation is one of the major reasons why object


programming is more reliable than structured programming

Chapter XVII Introduction to Object Oriented Programming 17.46


which passes data structure parameters to functions.

It is true that private data of a class should not be accessed by any function or
program statement that is not a member of the same class. That means that
modifying any private data is done my member functions of the same class. We
call such function modifier functions. Now we are really concerned that once
again data is only altered properly.

Consider program DECK11.CPP, which uses a ShowData function to display the


values of the object’s data fields (attributes). This function is a classic example of
an accessor function, which is a function that only accesses private data, but does
not modify anything. At least we would not expect a function that displays
information to modify any information.

Please do not ask why function ShowData includes assignment statements that
alter NumDecks and NumCards. This is a simple example to demonstrate that,
even though the data is in the private segment, I can rather easily modify the
values with any member function.

// DECK11.CPP
// This program shows how a function, which should be
strictly an
// "accessor" function, can modify private data. This
type of
// modification should to be avoided.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
public:
CardDeck(int,int);
void ShowData();
};

Chapter XVII Introduction to Object Oriented Programming 17.47


void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #11" << endl;
CardDeck D(4,5);
D.ShowData();
}

CardDeck::CardDeck(int ND, int NP)


{
NumDecks = ND;
NumPlayers = NP;
}

void CardDeck::ShowData()
{
cout << endl << endl;
cout << "SHOW DATA FUNCTION" << endl;
cout << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
NumDecks = 1; // NONO
NumPlayers = 2; // STATEMENTS
cout << "Attribute values after new assignment
values" << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
getch();
}

DECK11.CPP OUTPUT

CARD DECK PROGRAM STAGE #11

SHOW DATA FUNCTION

NumDecks: 4

Chapter XVII Introduction to Object Oriented Programming 17.48


NumPlayers: 5
Attribute values after new assignment values
NumDecks: 1
NumPlayers: 2

There is a neat safety-valve that can be used to make sure that a function,
designated to be only an accessing function, will not modify any data. The
function can be declared as a const function. Placing the reserved word const at
the right side the of the member function heading will insure that data is only
accessed, and not modified in any way.

Program DECK12.CPP repeats the previous program with the small addition of
the word const added to the ShowData function. Run this program the first time
with the “offending assignment statement” commented out. The program will run
fine, as long as no attempt is made to alter any data.

// DECK12.CPP
// This program demonstrates how to deliberately
prevent an
// accessing function from modifying private data. The
accessing
// function needs to be declared as a "const" function.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
public:
CardDeck(int,int);
void ShowData() const;
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #12" << endl;

Chapter XVII Introduction to Object Oriented Programming 17.49


CardDeck D(4,5);
D.ShowData();
}

CardDeck::CardDeck(int ND, int NP)


{
NumDecks = ND;
NumPlayers = NP;
}

void CardDeck::ShowData() const


{
cout << endl << endl;
cout << "SHOW DATA FUNCTION" << endl;
cout << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
// NumDecks = 1;
// NumPlayers = 2;
cout << "Attribute values after new assignment
values" << endl;
cout << "NumDecks: " << NumDecks << endl;
cout << "NumPlayers: " << NumPlayers << endl;
getch();
}

DECK12.CPP OUTPUT WITH ASSIGNMENTS COMMENTED OUT

CARD DECK PROGRAM STAGE #12

SHOW DATA FUNCTION

NumDecks: 4
NumPlayers: 5
Attribute values after new assignment values
NumDecks: 1
NumPlayers: 2

It is a different story when the comments are removed. This time the program
will not even compile and an error, like the one shown below, is generated.

Chapter XVII Introduction to Object Oriented Programming 17.50


DECK12.CPP OUTPUT WITH ASSIGNMENTS COMMENT REMOVED

Program does not compile and provides the following error message:

Compiling DECK12.CPP
Error DECK12.CPP 48: Cannot modify a const object
Error DECK12.CPP 49: Cannot modify a const object

The example of the previous program showed how a void function, like
ShowData, can be “locked in” to prevent unwanted data modification. The same
exact logic applies to return functions that are written to be strictly accessor
functions. The program is altered slightly and two return functions are now used
to display the data.

// DECK13.CPP
// This program demonstrates how to use return accessor
functions
// as const functions that cannot modify attributes.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
public:
int NumDecks;
int NumPlayers;
public:
CardDeck(int ND,int NP) { NumDecks = ND,
NumPlayers = NP; }
int GetDecks() const { return NumDecks; }
int GetPlayers() const { return NumPlayers; }
};

void main()
{
clrscr();

Chapter XVII Introduction to Object Oriented Programming 17.51


cout << "CARD DECK PROGRAM STAGE #13" << endl;
CardDeck D(4,5);
cout << endl;
cout << "There are " << D.GetDecks() << " card
decks." << endl;
cout << "There are " << D.GetPlayers() << " card
players."
<< endl;
getch();
}

DECK13.CPP OUTPUT

CARD DECK PROGRAM STAGE #13

There are 4 card decks.


There are 5 card players.

Object Oriented Programming and Reliability Notes

Program reliability is a major goal of object oriented


programming. Placing data in a private segment of a
class, such that only member functions can access the,
increases reliability.

The process of placing data and functions that access the


data in the same data structure is called encapsulation,
which is a fundamental object oriented programming
feature.

Reliability can be further enhanced by dividing member


functions into two groups of functions:

Modifiers (also called mutators), which may modify private


data, and accessors, which may not alter any data members.

Chapter XVII Introduction to Object Oriented Programming 17.52


All accessor functions should be declared as const functions
to prevent unintentional data modification.

Example:

int CardDeck::GetDecks() const


{
return NumDecks;
}

void CardDeck::ShowDecks() const


{
cout << NumDecks;
}

17.8 Overloading operator+=

You have learned in an earlier function chapter that functions can be overloaded.
It is possible to use the same function name and yet call different function
implementations. C++ manages to distinguish between the different functions by
looking at the function signatures. Different parameter types, and or different
quantities of parameters identify the desired function. This overloaded function
business was shown earlier in this chapter with the use of multiple constructors.

You will be pleased to know that C++ can overload operators besides functions.
The topic of overloaded operators is quite involved and in this chapter you will be
exposed to a brief introduction to give you a flavor of the concept and to make it
easier to study the concept in greater detail at some future date. Remember this is
an introductory, survey, chapter of object oriented programming.

Overloaded operators are not such an odd concept. You have used the plus
operator for quite some time in various contexts. Integer addition means that the

Chapter XVII Introduction to Object Oriented Programming 17.53


plus operator adds 10 + 20 and this equals 30. String concatenation means that
the plus operators concatenates ”Hello” + ”World” into the string ”HelloWorld”.

Before we investigate an actual overloaded operator declaration, let us first add a


new member function to the CardDeck class. This will be function Increment,
which is charged with the responsibility of incrementing the number of card decks
by a specified amount. Adding this type of functionality does not present any
new concepts, but it will set up an overloaded operator function.

// DECK14.CPP
// This program adds the Increment members function,
which
// increases the number of decks by a specified number.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
public:
int NumDecks;
int NumPlayers;
public:
CardDeck(int ND,int NP) { NumDecks = ND,
NumPlayers = NP; }
int GetDecks() const { return NumDecks; }
int GetPlayers() const { return NumPlayers; }
void Increment(int N) { NumDecks += N; }
};
void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #14" << endl;
CardDeck D(3,6);
cout << endl;
cout << "There are " << D.GetDecks() << " card
decks." << endl;
cout << "There are " << D.GetPlayers() << " card
players."
<< endl;
D.Increment(2);
cout << "After calling Increment function" << endl;
cout << "There are " << D.GetDecks() << " card

Chapter XVII Introduction to Object Oriented Programming 17.54


decks." << endl;
getch();
}

DECK14.CPP OUTPUT

CARD DECK PROGRAM STAGE #14

There are 3 card decks.


There are 6 card players.
After calling Increment function
There are 5 card decks.

There are no big surprises in program DECK14.CPP, but the stage is now set for
adding an overloaded operator. Our motivation is do exactly what was done in
the previous program with function Increment. The big difference is that we do
not want the usual dot.function notation like D.Increment(2). Our desire is
to use a statement, like D+=2 and this will increment in the precise same manner.

C++ allows this type of programming with the reserved word operator followed
by the operator that needs to be overloaded. For this chapter you will only be
learning how to overload an arithmetic assignment operator, like +=. The magic
of this special reserved word is that the operator following the word operator
performs the action that is designated in the body of the function. For instance,
the operator+= function below is shown implemented two ways. In both cases
the value of NumDecks is incremented by the value of N.

void operator+=(int N) { NumDecks += N; }

void CardDeck::operator+=(int N)
{
NumDecks += N;
}

Pay very close attention to the main function of program DECK15.CPP. The
main function calls the overloaded operator in two different ways. First, you will
see the familiar dot.function notation with the statement D.operator+=(1);

Chapter XVII Introduction to Object Oriented Programming 17.55


This syntax may seem weird, but it does follow precisely the manner in which
member functions of an object are called. Second, you will note overloaded
notation with the statement D+=1;

// DECK15.CPP
// This program uses the overloaded operator+= function
in
// place of the Increment function.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
public:
int NumDecks;
int NumPlayers;
public:
CardDeck(int ND,int NP) { NumDecks = ND,
NumPlayers = NP; }
int GetDecks() const { return NumDecks; }
int GetPlayers() const { return NumPlayers; }
void operator+=(int N) { NumDecks += N; }
};

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #15" << endl;
CardDeck D(3,6);
cout << endl;
cout << "There are " << D.GetDecks() << " card
decks." << endl;
cout << "There are " << D.GetPlayers() << " card
players."
<< endl;
cout << endl;
D.operator+=(1);
cout << "After using D.operator+=(1);" << endl;
cout << "There are " << D.GetDecks() << " card
decks." << endl;
D += 2;

Chapter XVII Introduction to Object Oriented Programming 17.56


cout << "After using D += 2;" << endl;
cout << "There are " << D.GetDecks() << " card
decks." << endl;
getch();
}

DECK15.CPP OUTPUT

CARD DECK PROGRAM STAGE #15

There are 3 card decks.


There are 6 card players.

After using D.operator+=(1);


There are 4 card decks.
After using D += 2;
There are 6 card decks.

Again, keep in mind that there are many other operators that can be overloaded
and there is much to be learned in this overloaded operator area. Study this
program example, absorb the logic and the syntax, and you will not be so
surprised when overloaded operators returns with serious reinforcements.

Overloaded Operator Notes:

The intention of overloaded operators is to allow the


convenience and readability of operator symbols to be
used by data types for situations that are not part of
the standard C++ functionality.

An operator becomes overloaded by using the reserved


word operator followed by the operator symbol. This makes
a member function that can be called in the conventional

Chapter XVII Introduction to Object Oriented Programming 17.57


dot.function notation or the overloaded function notation.

Consider the following member function:

void CardDeck::operator+=(int N)
{
NumDecks += N;
}

This function can be called using:

D.operator+=(5); or D+=5;

17.9 The Initializer List

This chapter is just going to be full of goodies that will have greater meaning at a
later stage. Even the last section of the object oriented introduction will hold true
to that philosophy. In this section you will learn that there is another way to pass
information to private data. Start by looking at program DECK16.CPP and
observe anything that looks different from materials that has already been shown.

// DECK16.CPP
// This program demonstrates how to pass use the
"intializer list"
// in the constructor to assign values to private data.

#include <iostream.h>
#include <conio.h>

class CardDeck
{
private:
int NumDecks;
int NumPlayers;
public:
CardDeck(int ND,int NP);
int GetDecks() const { return NumDecks; }
int GetPlayers() const { return NumPlayers; }
};

Chapter XVII Introduction to Object Oriented Programming 17.58


CardDeck::CardDeck(int ND, int NP)
: NumDecks(ND), NumPlayers(NP)
{
}

void main()
{
clrscr();
cout << "CARD DECK PROGRAM STAGE #16" << endl;
CardDeck D(3,6);
cout << endl;
cout << "There are " << D.GetDecks() << " card
decks." << endl;
cout << "There are " << D.GetPlayers() << " card
players."
<< endl;
getch();
}

DECK16.CPP OUTPUT

CARD DECK PROGRAM STAGE #16

There are 3 card decks.


There are 6 card players.

Careful observes will notice that the constructor shows some odd looking syntax.
The execution of the program is fine, but the constructor is just a little bit on the
weird side. In this program the purpose of the constructor is to initialize values
for NumDecks and NumPlayers. A constructor, like the one shown below, will
perform that job quite nicely.

CardDeck::CardDeck(int ND, int NP)

Chapter XVII Introduction to Object Oriented Programming 17.59


{
NumDecks = ND;
NumPlayers = ND;
}

I am sure that you are not pleased that a nice, simple constructor is now altered to
some strange looking function. It is a style of constructor that uses the so called
initializer list. By using a colon after the function heading, and following this
colon with some special program statement, it is possible to pass information to
the data members of an object with the conventional assignment approach. This
initializer list approach is shown below.

CardDeck::CardDeck(int ND, int NP)


: NumDecks(ND), NumPlayers(NP)
{
}

I can just hear all the why, why, why questions popping up. Excellent question,
and at this level there is no justification for using the initializer list. There is some
value because the initializer list processes faster than the assignment statements,
but that is not much motivation to come up with another approach. Have a little
patience because the very next chapter will show some program examples that
involves constructors that must use the initializer list approach.

APCS Examination Alert

Object Oriented Programming (OOP) is part of the A and the


AB APCS Examination.

Students preparing for the A Examination are expected to


use provided classes proficiently. Furthermore, students
are expected to alter the functionality of member functions,
and add new member functions to an existing class.

Students preparing for the AB Examination are expected to


have a sophisticated knowledge of OOP. The details of
this required OOP knowledge will be explained in

Chapter XVII Introduction to Object Oriented Programming 17.60


later chapters for second year AB students.

Chapter XVII Introduction to Object Oriented Programming 17.61

You might also like