Вы находитесь на странице: 1из 66

Object-Oriented Programming in C++

Module

Quick Overview

0
Written by Ron House
csc2402 — Object-Oriented Programming in C++ Study Guide

1.1 Introduction

Object-oriented programming (O OP) is a method for designing, constructing and maintaining so ftware. Prev iously
your programs were written as a sequence of instructions that were executed one after the other. The OOP method
of software construction considers a program as a set of interacting ‘objects’. This course is designed to extend your
knowledge of programming tech niques beyond the procedural programming paradigm into the object-oriented
paradigm. It is assumed that you have studied course csc1401 or an equivalent, in order to gain an understanding
of the C language and to o btain skills in procedural program ming techniques.

This cou rse is also intend ed to pro vide you with so und prog ramming sk ills in C++. Many new features have been
added to C++ with the release of the new ISO standard, in particular the string feature and the stan dard tem plate
library (STL). W e shall be looking at these in detail, because using them co rrectly can ma ke it very much easier to
write correct and powerful C++ programs. In fact, these features eliminate some of the biggest problems with old-
style C++ prog ramming. Therefo re this course is designed to se rve two purposes: to teach you object-oriented
programming skills, and to help you master the very latest techniques in C++ programming.

Because of the great usefulness of many of the new C++ featu res, we shall study most of these prior to studying
object-oriented pro gramming techniques.

In this course, you will be expected to adopt a certain style of layout and documentation which is design ed to aid the
goal of creating reliable, well-structure d progra ms that can be easily understo od and m odified. Y ou will find this
style described in Appendix A of this study guide. It is a requir ement of this co urse is that you sho uld follow this
style. This is not optiona l! This style do es help to write clear and error-free programs, but more importantly, many
employers have their own standards for writing pro grams, and they will expect the ir employee s to follow their
standards. If yo u ar e un abl e to con form to a spe cific style now , you will h ave trou ble con form ing t o an emp loye r's
style later.

1.2 What is Covered in the Course?

The course co vers Chap ters 1 throug h 8 of the text, Object-Oriented Programming in C++, 2 nd edition, by
Johnsonbaugh and Kalin. Additional material will be provided in these notes. (The 2nd edition of the te xt is
substantially different from the 1 st edition, which does not co ver the new C ++ standa rd describ ed below .)

1.3 The C++ Language

C++ was designed by Bjarne Stroustrup as a successor to C, and is becoming increasingly popular. In particular,
most of the commercial software ava ilable today w as written in C+ +. C++ adds ma ny new feature s to C (partic ularly
classes, used in object-oriented programming), but in addition, it bans many of those olde r, poorer fe atures of C. T his
fact is not well-know n. I have often r ead in mag azines, etc., that C ++ is a supe rset of C. It isn't. Not just any C
program will compile and work using a C++ compiler. But programs using the modern features of ISO C will work
correctly under a C++ com piler. If you have studied C and followed my advice to stick to the better parts of the C
language (particularly those taught in the book, Beginning with C; then your C programs should run correctly as C++
programs without modification.

0.2
csc2402 — Object-Oriented Programming in C++ Study Guide

The above fact points out an important thing about C++: it is not exclusively an object-oriented language; you can
write old-style function-oriented programs or object-oriented programs in C++. You can even m ix the two styles in
the one program.

1.4 Compilers and Software

For more information, please see the Introductory Booklet or, for the latest information, the course web site.

If you are studying internally, you will be able to use the software in the USQ laboratories.

1.5 The Subsequent Modules

In the modules that follow, you will see activity boxes like this one:

Reading and exercise


Study ... .

When you reach such a box, please do the reading or the activity. You can't learn programming without actively
writing programs; just following someo ne else's program in a textbook is not enough.

You will also see boxe s such as:

Summative Practical Exercises

These boxes tell you which practical exercises you must do to be awarded the marks for practical work. You should
try to get all such exercises complete and working every week; do not allow them to “pile up”, as consistent work
is both easier and more e ffective than cram sessions.

External and Online Students should send in listings of their programs; these will be awarded marks for having
been do ne, but they will not be graded or marked.

Internal students might be assig ned differen t exercises in class ; if so, they will take precedence over the work
shown in this study guide. Attendance at the tutorials and practicals will also be required.

0.3
csc2402 — Object-Oriented Programming in C++ Study Guide

1.6 Books

An increasing number of books and textbooks are being produced covering object-oriented programming and/or
C++ . Here a re a few that yo u ma y wan t to take a look at.

Breymann, Ulrich. Design ing Com ponen ts with the C++ STL, revised edition. Addison Wesley 2 000. (A n in-depth
coverage of the STL , a very impo rtant and usefu l part of the new C++ stan dard.)

Budd, Timothy. Data Structures in C++ usin g the Standa rd Template L ibrary. Addison Wesley 1 997. (C overs data
structures using th e C++ S TL.)

Hende rson-Sellers, B rian. A Book of Object-Oriented Knowledge. Prentice Hall 1992. (Not a C++ book. Focuses
on software lifecycle/design issu es.)

Meyer, Bertrand . Object-Oriented Software Construction. (A very good book about OO, based on Meyer's language,
Eiffel.)

Stroustrup, Bjarne. The C++ Programming Lang uage 3 rd edition. Addison Wesley 1997. (From the design er of C++,
this is the definitive book on the language. This edition describes the new standard C++; earlier editions differ
significantly.)

0.4
Object-Oriented Programming in C++

Module

Basics of
Object-Oriented

1
Programming

Written by Ron House


csc2402 — Object-Oriented Programming in C++ Study Guide

Fools igno re comp lexity. Pragma tists suffer it.


Some ca n avoid it. Ge niuses remo ve it.
-- Perlis's Programming Proverb #58, SIGPLAN Notices, Sept. 1982

[Some a dditional m aterial in this mod ule was written b y Anne Fuller .]

1.1 Introduction

In this module we take a preliminary look at the basic ideas of object-oriented programming so that you
can keep them in mind whilst we study some features of C++ in the next few modules; then we shall return
to study these OO principles in more detail later.

Object-oriented programming (OOP) is a method for creating and maintaining software. A lot of hype has been
spoken and written ab out it, but it is not a ma gic bullet, and it d oes not gua rantee that software will be good or
efficient. However, O O methods can permit better organisation of the structure of software so that it can be more
easily understood, maintained, and enhanced. Also, greater re-use of software will be possible.

Previous ly your programs were written as a sequence of instructions that were executed one after the other. The OOP
method o f software con struction con siders a pro gram as a set o f interacting ‘obj ects’.

Object-oriented program ming focuse s on the data that is processed by a program, rather than on the algorithms that
the program processes the data with. The hope is that the data is mo re stable than th e algorithms, so program s will
be easier to write and to maintain when circumstances change.

1.2 Software Design

Software design is generally regarded as harder than writing the programs themselves. Errors in the design are much
harder to fix if lef t und isco ver ed u ntil t he c odi ng p has e. M any d iffer ent ` mod els' o f software design are used and
advoca ted.

The difficulty is that most estab lished (non-o bject-orien ted) design m ethods do n't easily carry over to OO, and OO
software de sign method s still have many ro ugh edges .

The trad itional appro ach to softwa re creation u ses the `Lifecycle' ap proach:

Analy sis
.))),
.))),
.
Design
.))),
.))),
.
Implementation

This is called the “waterfall” m odel.

The analysis phase is intended to identify what the software should do. I.e. obtain softw are require ments.

1.2
csc2402 — Object-Oriented Programming in C++ Study Guide

The design phase identifies how the software will sa tisfy the requirements: find algorithms and data structures that
perform a s required.

The implementation phase involves writing and testing the software that implements the design.

1.3 Design Methods

Structured analysis (by De Ma rco) concentrates on ho w data flows through the system. It uses data flow diagrams
(DFD s), data dictionaries, and minispecifications.

DFD s identify proce sses and da ta flows throug h the system. See Figure 3.2 in the text.

A data d ictionary hold s descriptio ns of the da ta items.

The min ispecification d escribes the p rocesses in E nglish.

Structure charts (by Larry Constantine) are basically, just a structured version of the flowchart. They capture logic
as a deco mposition from a single to p-level mod ule. See Fig 3 .3 in the text.

1.4 Problems with the Top-down Approach

Some problems identified with these traditional techniques are: It is hard to allow for evolutionary changes in
software, not all systems really do have a top-level function, they focus on functions at the expense of data, they do
not facilitate reusability, as modules are usually written to satisfy specific requirements of higher mod ules.

1.5 Post-waterfall Models of Software Lifecycles

Recently, people have gained a greater understanding of iterative develop ment: this include s the use of prototypes,
or working models, of software: maintenance of accurate design in parallel with developing programs — a series
of prototyp es mode lling the system incre asingly accura tely, with working p rograms a t each stage.

These methods are evolutionary .

The ob ject-oriented approa ch to the traditio nal three steps m ight be as follow s:

Object-or iented analysis:

Specify system requireme nts in terms of rea l-world ob jects: how they b ehave and interact.

Object-oriented design:

Design sp ecifications for c lass hierarchie s in terms of ob jects that emer ged from a nalysis.

1.3
csc2402 — Object-Oriented Programming in C++ Study Guide

Object-oriented programming:

Impleme ntation is in a pro gramming language suc h as C++ .

Some people argue that the design and programming can be conflated: the design should be captured in the program.
For example, Bertrand Meyer's Eiffel language allows the preconditions and postconditions of methods to be
specified and checked by the compiler and/or the run-time system.

1.6 Illustration: Writing a Graphics Program

Let us start by seeing h ow a grap hics progra m that manip ulates geom etric shapes m ight be written in the old ,
function-oriented method. W e would define functions for entering shap es, storing on disk, editing, moving shapes,
drawing on screen, etc.

Suppose the program is originally designed to handle circles and squares. One day, the boss rushes in and tells us
to add triangles to the program . To do this, we would have to edit almost every part of the program: add triangles
to the data-entry function, add triangles to disk storage routines, add triangles to editing functions, add triangles to
moving routines, add triangles to scre en-drawing routines, etc. Almost every part of the program might need to be
altered, just to add one more shape. The possibilities for errors are ob vious.

The object-oriented method, on the other hand, would suggest starting by defining objects for each shape: circles
and squares. Each object understands how it is created (for example, mouse clicks to define the object), how to store
itself on disk, how to be moved, how to display on the screen, etc. Now what happens when the boss rushes in telling
us to add triangles? To add the new shape, we would leave the existing parts of the program und isturbed, and just
write code for a new triangle object, containing only the code for operating on triangles. Possibilities for adding
errors to old working code are eliminated.

1.7 Main Concepts of Object-Oriented Programming

Object-oriented p rogramming con sists of three main concepts:

* Data abstraction - including Ab stract Data Types (AD Ts)

* Inheritance

* Polymorphism.

These will be discussed in the follow ing sections.

1.4
csc2402 — Object-Oriented Programming in C++ Study Guide

1.8 Abstract Data Types:

An Abstract Data Type is a data type defined in terms of the operations that can be performed on or using
the data, not in terms of the structure of the data.

An abstract data type (ADT) encapsulates the data by `insula ting' us from the itsy-bitsy de tails of how the d ata is
stored.

Example of NON ADT:

Definition of a complex number: A struct containing two fields, re and im, standing for the real and
imaginary parts.

The disadvantage of this definition is that if we change our minds and decide to store the complex number in a
different format (for example, polar co-ordinates using r and 2), any program using our complex numbers will need
to be changed to remove references to re and im, and replace them with r and theta.

The prog ram logic w ill need to be altered a t every place w here this occurs.

Example of an ADT:

Definition of a complex number: An object with mathematical operators (+, -, *, / etc.) that behave as
approp riate for complex numb ers (which would have to b e explained further), with functions re() and
im() that return the real and im aginary parts of the number, and with a function create(r,i) that
creates a co mplex num ber out of two real numbe rs, r and i.

W e have to think out the design of the complex number ADT properly before we launch into writing the program.
This takes time, but has paybacks later on in easier development and re-use.

W e can replace the `innards' of the complex number data type (such as replacing re and im with r and theta)
without changing any program that uses the data type.

Example of NON ADT:

Definition of a stack of intege rs: An array of 100 ints, with a stack pointer, an int called p, which
stores the array index of the element on the top of the stack.

This is the usual sort of definition we would normally expect. However, with this definition, we must write code that
explicitly handles the array and the stack pointer in or der to use the stack. Non e of our wo rk is re-usable if we decide
to have a stac k of someth ing else, or eve n a differently-arran ged, stack o f ints.

Example of an ADT:

Definition of a stack of intege rs: An object with functions create to create an e mpty stack, push to
put an integer on to the top o f the stack, size to report ho w many items a re in the stack, pop to remove
the top item on the stack, etc.

With this definition, we can re-use the code in other projects, create stacks of other sorts of things, alter the way
stacks are implemented, etc.

1.5
csc2402 — Object-Oriented Programming in C++ Study Guide

Key point: ADTs are definitions of data types; they scrupulously avoid revealing information about the internal
structure, algorithms, etc.

Classes and Objects

An object is a single data item. For example, a person object called Joe would contain all the data for a particular
person. A class, however, describes any and all objects belonging to the class. Thus a class called person describes
any person, not just Joe.

The relationship of Joe to person is exactly the same as the relationship of an integer variable called count to
the data type, int. That is, Joe is a particular person, just as count is a particular int.

What we define in our programs are classes; the things that exist when the program runs are objects .

This is a very importa nt distinction ; you m ust becom e familiar w ith it.

1.9 Inheritance

Inheritance is the ability to define ne w objects b y adding to o r changing o bjects that alre ady exist.

Suppose you were asked to design a vehicle ADT in C. One way to do this appears below.

struct vehicle {
char make[15];
int num_wheels;
int year;
};

typedef struct automobile car;

/* define some operations e.g. drive(), start() etc. */

Now suppose you are aske d to design another AD T to represent a taxi. For a taxi we also need to calculate the fare.
To associate a fare with a car we need to either rewrite the above struct, adding an additional fare field, or create a
new struct that has a car in one fie ld, and the fare as an additional field. In both cases we will need to rewrite the
functions that use d the origina l struct.

In C there is no mechanism for representing ADTs that describe similar sets of objects. We needed to define a new
set of operations for the new A DT, even thou gh many of the operations o n a car are also applicab le to a taxi. In OO
languages we can actually describe a relationship between these AD Ts and u se all the oper ations defined in the car
ADT in the ADT for a taxi. This relationship is created by deriving a new ADT from another and is known as
inheritance.

Instead of having to write a complete new ADT for a taxi, we can inherit t he car AD T and the n we need only
implement the operation s where a taxi d iffers from a car. In the taxi/car case we would n eed to add an o peration to
calculate fare and also modify the definition of start() to not only start the motor but also allow us to start the meter
running.

Mu ltiple inheritance: this occurs when an object is an example of two or more other types of objects. For example,
we might classify art into sculpture, paintings, etc. We might classify pottery into plates, cups, dishes, etc. A limited
edition art plate will be both a painting and a plate, and will have features of both.

Multiple inh eritance is not su pported in all OO lan guages. It is supported in C++.

1.6
csc2402 — Object-Oriented Programming in C++ Study Guide

1.10 Polymorphism

Polymorp hism literally means “many forms”. It refers to the ability to perform operations without knowing
the type of object that will be operated on.

For example, in the graphics program, the display module might execute the display operation for an object; if the
object is a triangle, then triangle's display function will execute. If the object is a square, then
square's display function will execute.

Examples of polymorphism:

N Maths operators in ordinary programming languages (for example, `+' works on ints, floats, etc.)

N Many languages have one input or output statement that will transfer any kind of built-in data value.

The above, however, are only limited forms of polymorphism because they are detected at compile-time. The more
flexible version available in OO languages allows the system to detect different types at runtime. Suppose we are
asked to write a progra m that simulates tra ffic in a city centre to stud y the affects of installing a new set of traffic
lights. Clearly we will have numerous types of vehicles; buses, trucks as well as taxis and cars. Suppose the following
tree describes the inheritance relationship between these different kinds of vehicle.

Vehicle
/ | \
/ | \
/ | \
Car Truck Bus
|
|
|
Taxi

We m ight simulate the tra ffic flow in one stree t using an array o f pointers to the vehicles enterin g the street.

vehicle* first_street[100];

As the simulation p roceeds (i.e. as the prog ram execu tes) this array will con tain pointers to cars, buses o r taxis etc
at various times. We ca n write code to process the array of vehicles without knowing what kind of vehicle we have.

for (i = 0; i < 100; i++) {


first_street[i]-> drive();
}

All we need to know is that any class derived from vehicle has a drive() operation defined. We do not need to
know whether we will have a car, taxi, bus or truck for this loop to work. Not only tha t, we can subse quently
add other vehicles to the simulation e.g. a semi trailer or a delivery van, without having to make any changes to this
loop.

1.7
csc2402 — Object-Oriented Programming in C++ Study Guide

1.11 Object Oriented Design

Finding the objects you need to model your solution is one of the skills you will need to develop in this course. The
best place to start is with objects that exist in the real world. e.g. Suppose we are writing a program to enable the
university library to keep borrower details in order and keep track of items borro wed. W e can reco gnise immed iately
that a real world object involved in this system is a borrower. Another set of objects that exist in the real world that
will probably form part of this solution are b ooks.

Our next step is to describe these real world objects as computer world objects. This involves analysing the real
world object to determin e what aspe cts of the obj ect are releva nt to the prob lem. e.g. A bo rrower is a p erson. A
library is most likely interested in the person’s name, address and the list of books he/she curren tly has on loan. A
library is unlikely to be concerned about a person’s weight or sex; howeve r, if we were writing a program to help
a doctor k eep track o f patients' medica l histories, these attrib utes would b e importan t.

The process o f decid ing what parts of a real world object are essential to modelling the solution to a particular
problem is called abstraction.

Abstraction is not just about describing an object’s attributes. Objects also have behaviours i.e. things that an object
can do. e.g. A person can run, jump, swim. These behaviours are irrelevant to our library application. A person can
borrow or return or r eserve a libra ry book. T hese beha viours are rele vant.

Inanimate objects also have behaviours. A book can be borrowed, returned, or reserved. Modelling these behaviours
is part of the library application. A book can also be read, bought or sold, its pages turned. These behaviours are not
part of the current problem.

Object-oriented design is a skill. Some of you will be better at it than others. Although there are methodologies that
can help in this pro cess, they are p articularly helpfu l for larger pro jects involving many different designers and not
necessary for the smaller projects we will be undertaking. The best way to learn is to look at as many examples as
you can. We w ill also give you some rules which cover wh at is not OO design.

1.12 Message-Passing Paradigm

Many OO books talk a bout mess ages beca use these wer e used in Sm alltalk. Howe ver, the messa ge idea is not central
to object-oriented programming. Unfortunately the Johnsonbaugh and Kalin (J&K) also goes co mpletely off the rails
in Chapter 1, making the huge mistake of treating messages as an important idea. Forget about this entirely, it's a red
herring that originated because Smalltalk (a language with significant deficiencies) had them as a central idea. The
real basics of OO methodology are abstract data types (ADTs), inheritance, and polymorphism.

The idea behind messag es is this: suppose we want an object to execute its au to-incremen t function (i.e. ++). For
example:

count++;

W e can think of this as sending a `message' to count telling it to add 1 to itself. Clearly, this adds noth ing that is
not already included in the idea of polymorphism.

1.8
csc2402 — Object-Oriented Programming in C++ Study Guide

1.13 The Object-Oriented Programming Style

Non-O-O programs tend to have large switch or if statements to handle all the different cases that can arise:

void display(sometype obj) {


switch (obj.kind) {
case SQUARE:
...
break;
case CIRCLE
...
break;
case TRIANGLE:
...
}
}

This style requires editing working functions whenever anything changes or when new datatypes are added (such
as new shapes in the above). OO programs tend to have many small functions, each of which handles just one of the
functions (methods) for a single datatype:

void SQUARE :: display() {


... // Code to display a square
}

void CIRCLE :: display() {


... // Code to display a circle
}

void TRIANGLE :: display() {


... // Code to display a triangle
}

This style does not require editing working functions when something changes, or when new data types are added
(such as new shapes in the above). To add new shapes, we d efine a new cla ss (we'll learn how la ter on) and write
functions to handle the various tasks for that new class.

1.14 Hybrid Design Methods

These a re method s that comb ine objec t-oriented an d non-ob ject-oriented techniques fo r some rea son:

Reasons:

Need to use existing non -object-oriented libraries

Need to use existing ob ject-oriented classes in prog rams that are b est written function ally

Desire to u se most ap propriate method in d ifferent parts of a p roject.

1.9
csc2402 — Object-Oriented Programming in C++ Study Guide

Some possibilities:

- An overall ob ject-oriented progra m, whe re code in some m ethods is written in functional top-down style.
Might suit a system where object-oriented behaviour is appropriate, but some methods involve tricky logic.

- Top-dow n functions con trolling interactions of ob jects.

- An object-oriented set of classes providing access to an underlying function library. Best where standard
non-object-oriented library alread y exists.

1.15 Putting It All Together

To solve a problem: First look for a ll the objects that the problem involves. For example, the university's student
record system involves students, courses, degrees, etc.

Next design spec ifications for all the things that these o bjects can d o and all the p roperties the y possess - e.g. a
student has a nam e, address, can enrol, withdraw, drop a course, add a course, get a grade, etc. A degree can have
courses, majors, etc. A course can have a name, belong to a department , etc.

The program works by asking the vario us objects to `do their tricks' - e.g. tell a student object to drop course A and
add course B, etc.

1.16 Example

Keeping tr ack of books lo aned to friend s:

I have a number of books that I might lend to my colleagues. How could I keep track of them?

Objects: persons, b ooks.

OK: Each bo ok might hav e a borro wer, each b orrower m ight have a set o f books cu rrently borro wed.

Therefore: New object: the set.

Design:

Each person will contain a set of references to books.

Each book will have a reference to the person who has bo rrowed it.

Each set will know how to store collec tions of items, ad d new items, re move item s, etc.

Now all you have to do is program it in C++.

1.10
csc2402 — Object-Oriented Programming in C++ Study Guide

1.17 Reading

The ma terial discussed here is cove red in the text.

Study
The m aterial discu ssed h ere is cov ered in C hapter 1 o f the text, Object-Oriented
Programming in C++, by Johns onbau gh and K alin. (W e will call it "J&K" fro m no w on.)
Study this material now before proceeding with the following modules, but note that
there are some serious errors in this chapter (in particular "Polymorphism and
Recursion") see my comments about this below.

Warning about J&K chapter 1:

There is some very unsound material in chapter 1 of the text (although the rest of the bo ok seems re asonable ). The
authors seem to have succumbed to the temptation to latch on to all the fashionable buzzwords rather than focus on
the essentials.

Here are the essen tials:

1. Classes and abstract data types


2. Inheritance
3. Polymorphism

Here are the flaky b uzzwords:

A. The client/server model


B. Message passing

Object-oriented programming is based on a wonderful synergy operating among the three essentials listed above.

Abstract data types (implemented as classes in C++) allow us to program objects so as to provide an interface
without exposing the innards of how the object actually does its job. For example, numbers can be added, subtracted,
multiplied, displayed, input, etc. As long as numbers do these things correctly, it doesn't matter to us how the number
is stored or how the com puter implements the algorithms for the o perations.

Inheritance allows us to say "this new object is like that old one, except for a few differences". For example, a taxi
is like a car, except that it also has a taxi licence, a little sign on top, etc.

Polymorphism allows the system to automatically select the correct operations for the object concerned at runtime.
For example, a taxi is allowed to go in special taxi lanes on some ro ads; a 'drive' function in the taxi class will allow
the taxi to en ter the tax i lane, whe reas the 'drive' functi on in the car class won't; the system will pick the correct drive
function at runtime depending on whether a taxi or an ordinary car is involved.

1.11
csc2402 — Object-Oriented Programming in C++ Study Guide

Specific Errors in Chapter 1

The client/server model is a useful computing concept, and is very important under some circumstances (even some
circumstances involving OO programming). However it is not a fundamental part of the OO paradigm, and trying
to make it look as if it is by portraying every object as a 'server' is not very pro ductive. In o ne sense it is perfe ctly
true (about as true, for example, as calling the Pacific Ocean a large puddle) but doing so distorts the facts and serves
no useful purpose.

As mentioned earlier, the message-passing paradigm is not an essential part of OO programming. It is an


unproductive concept. For example, the book says that "buffer.insert(...)" is passing the "insert" message to the object
"buffer". Whatever makes you happy. But what is actually happening is simply this: objects can own, not only data,
but also functions (called, in OO terms, methods). "insert" is a method (or function) owned by "buffer", and the
above piece of code simply calls the "insert" method that "buffer" owns. That is all that is happening.

Finally, one of the sections in chapter 1 is titled "Polymorphism and Recursion". I couldn't guess what possessed
the authors when they wrote this section. Recursion is a programming technique that can be used in both OO and
non-OO programs; it has nothing whatsoever to do with polymorphism. Recursion is the direct or indirect calling
of a function from within itself; polymorphism is the ability to dynamically select the correct version of a routine for
execution, depending on the type of data being operated on at runtime. The example in the text showing how
polymorphism is somehow 'better' than something it is totally unrelated to is nonsensical. The fact is, a good OO
design will probably simplify most logic of most programs, and therefore it will pro bably simp lify recursive logic
also. The example they show is only incidentally related to recursion, and in fact is just a particular case of how
polymorphism tends to simplify things. Setting recursion up as some sort of straw man to be knocked over by
polymorphism is ludicrous. Finally, their comment in this section that "Recurs ive functions ar e notoriou sly hard to
write precisely because they typically require complex, difficult logic" is thoughtless and stupid; any competent
computer scientist will know that ma ny recursive alg orithms are e legant and v astly easier to und erstand than their
iterative counterparts. I must confess that, after reading this section, I was amazed that the rest of the book seems
to be reaso nably com petent.

1.18 Exercises

Here are some questions for you to ponder. There are no `solutions' to these problems because there are many
possible right (or wrong) ways to tackle them. The important thing is to carefully think out your reasons for your
answers and write them down.

1. You have been hired to write the contro lling program for a comp uter-controlle d lawn mo wer. Ma ke a list of all
the functions you think the lawn mower should be able to execute.

2. In the C programming language, list any feature or other item you can think of that is (or is a lmost) obj ect-
oriented. T hat is, it is like a class in that we don't need to know its innards, only how to execute the methods (that
is, call the functions) that make the thing `do its tricks'. Explain why this feature is (nearly) object-oriented.

3. In the C programm ing language, list any feature or other item you can think of that is not (that is, not even almost)
object-oriented. Explain why this feature is not (even nearly) object-oriented. Don't be worried if you want to put
some feature here as well as in question 2 above!

4. (Harder) It is possible to get the advantages of OO progr amming in C, if you work hard enough! Consider the
following problem (simplified version of the problem of displaying objects on a screen). Suppose we have two
structs, defined as follows:

struct triangle {
double side_1, side_2, side_3; // lengths of the three sides

1.12
csc2402 — Object-Oriented Programming in C++ Study Guide

};

struct rectangle {
double length, height;
};

Now suppose we have an array of void pointers vp, each of which points to either a triangle or a rectangle, and
we have an arra y of int indicators, typ, each element of which tells us the type of the item pointed to by the
corresponding element in vp. For example, if typ[3] equals 1, then vp[3] points to a trian gle, but if typ[3]
equals 2, then vp[3] points to a rectangle.

We might write a simp le ‘display’ function for this system as follows:

void display(int which) {


switch (typ[which]) {
case 1: triangle_display(vp[which]); break;
case 2: rectangle_display(vp[which]); break;
}
};

Clearly, adding a ne w shape to th is program involves editing this display function. Your challenge: can you think
of a better alternative to the typ array used above, that will permit you to write a display function that does not
require editing to add a new shape?

Summative Practical Exercises


There are no summative exercises for this module.

1.13
csc2402 — Object-Oriented Programming in C++ Study Guide

1.14
Object-Oriented Programming in C++

Module

C and C++

2
Written by Ron House
csc2402 — Object-Oriented Programming in C++ Study Guide

2.1 Introduction

Our plan is to first study the advanced programming facilities available in C++ before proceeding to study
OO programming in detail. But keep the OO ideas introduced in the previous chapter in mind as we
proceed.

C++ was developed in early 1980s by Bjarne Stroustrup. (AT&T). It was formulated by adding object-oriented (and
other) features to C, and removing a few bad C features. The primary inspiration came from the language Simula
67. (The 67 here stands for 1967, so object-oriented ideas had certainly been around for a long time before `catching
on'.)

The first commercial release of C++ was in 1985. T he first implementation was cfront: a translator from C++ to C.
Now, many native C++ compilers exist: these are compilers that translate directly into machine code for the computer
concerne d.

A standard sp ecification for C ++ has no w been pu blished: ISO/IEC 14 882, S tandard for the C++ Programming
Language. This is the version of C++ described by the third edition of Stroustrup 's book, The C++ Programming
Language. If you try to buy a copy of this second-hand, do not make the mistake of getting an earlier version, as
there are major differences.

2.2 C Language Features

You should be fully conversant with the C language before commencing this course. If there are any weak
spots in your k nowledge or skills, here is you r chance to c atch up.

Private study
You mus t be familiar with all the basic features of the C language ; if not, or if you are
rusty, please revise using a text such as Beginning with C. In any case, keep such a text
handy as you work through this course.

Points to specially note:

- Structure of a C program

- Pointers

- Type q ualifiers: const and volatile.

- Function prototypes

It is worth noting that function prototypes were introduced into ANSI C after they had been introduced by Stroustrup
in C++. Prior to this, C had an unsafe method of declaring functions and their prototypes, and programmers had to
be very careful when calling functions, otherwise the wrong machine code would be emitted by the compiler. ANSI
C provides both the safe and the unsafe method, but C++ only provides the safe method. Therefore, C programs that
use the old m ethod mu st be rewritten fo r C++. H ere is a comp arison of som e examp les of both m ethods:

2.2
csc2402 — Object-Oriented Programming in C++ Study Guide

Previous method: ANSI method:

int fred(); int fred(float, int);

int fred(a,b) int fred(float a, int b) {


float a; int b; ...
{ }
...
}

2.3 Differences between C and C++

Let 's start by listing some important differences between C and C++. This section and the next (new C++
features) will be presen ted as quick -fire items; after that w e'll have a look at some program examples.
Do n't spend too much time on this section in your first reading; you can come back later to check up on
things when you are writing your progra ms.

1. The old C function heading (discussed above) is prohibited in C++. Furthermore, all functions must be
prototyped before they are used (either by a prototype o r because the function itself has appeared in the source
file).
2. There are new re served keywords:

and and_eq asm bitand bitor


bool catch class compl const_cast
delete dynamic_cast explicit export false
friend inline mutable namespace new
not not_eq operator or or_eq
private protected public reinterpret_cast template
this throw true try typeid
typename using virtual wchar_t xor
xor_eq

If you have used any of these word s as identifiers in a C program , they must be alte red or they w ill not comp ile
under a C ++ com piler. [See J& K page 78 for the co mplete keyw ord list.]

3. Empty argument lists in function prototypes. In C, the declaration:


int fred();

means “W e do n't know wha t the argumen ts to fred are.” But in C++, it means “fred has no argu ments.”
[See J&K page 56]

4. Difference in const:

C: const with variable d eclarations m erely creates a v ariable who se value can not be cha nged.

C++: const with variable d eclarations c reates a con stant value kno wn to the com piler.

For exam ple,

2.3
csc2402 — Object-Oriented Programming in C++ Study Guide

const int size = 32;


float arr[size]; // Illegal in C but
// Legal in C++.

Therefore, in C++, use const in preference to #define wherever possible.

5. void pointers: C allows automatic assignment of a void pointer to any other pointer type and also any other
pointer type to a void pointer, but C++ only allows automatic assignment of any other pointer type to a void
pointer. For example:
void *vp; int* ip;
vp = ip; // Legal C and C++
ip = vp; // Legal C, illegal C++
ip = (int*)vp; // Legal C and C++
Initialising character arrays: C++ does not allow chopping the nul character off a string in an initialisation:
6.

char name[3] = "C++"; // Illegal C++


char name[3] = {'C','+','+'}; // Legal C++
char name[] = "C++"; // Legal C++
char name[4] = "C++"; // Legal C++
Arithmetic: C++ does not perform unnecessary conversions to int type. For example, sizeof('T') is the
7.
same as sizeof(char) in C++, but it is the same as sizeof(int) in C.

8. enum works better in C++. (The scope of enum constants is pro perly scop ed, rather tha n global.) [See J&K
page 41]
9. C++ d oesn't allow the us e of goto to jump into a block.

2.4 New Features in C++

This is a quick-fire list of some of the most important additions to C++ that are not present in C. Many
of these will be illustrated in the example programs, and many are explained in more detail in later
modules.

1. Classes (of course — heaps of features here, which we shall discuss a lot more later).
2. Reference Types: T hese eliminate some of the need for po inters. Wh en calling functio ns in C , all argum ents
are passed by value, meaning that the value of any variable is copied into the function. For example:
void twice(int *a) {
*a *= 2;
}
...
int x = 10;
twice(&x);
/* Here, x is 20 */

In the above, the address o f x (&x) is copied into twice as the argum ent a. This results in ugly "&" operators
wherever twice is called and ugly "*" operators inside twice wherever a is used. But with references,
instead of copying a value, a reference to the variable itself is passed in to the function. Therefore in C++ we
can write the above as:

void twice(int &a) {


a *= 2;
}
...

2.4
csc2402 — Object-Oriented Programming in C++ Study Guide

int x = 10;
twice(x);
/* Here, x is 20 */

All the ugly operators are eliminated, yet the code does the same thing. [See J&K pages 58-61]

3. Inline functions: These are substituted in toto each time they are called. No rmally a function is translated into
a single block of code, which is called v ia a proce dure call. Inline fu nctions are no t called in this way; instead
their code is actually inserted into the program on each occasion when they are used. They are very efficient,
at the cost of u sing more sp ace in the executable, but they do not have any different effect from a normal
function.
inline int sqr(int x) {
return x * x;
}

Inline functions should be fairly small. [See J&K page 62]

4. Default function arguments. Default values can be specified in case arguments are omitted.

void setup(int height=100, int width=50) {


...
}
Here, the default height is 100 and the default width is 50. So:

setup(); is the same as setup(100,50);


setup(75); is the same as setup(75,50);

This feature simplifies things such as writing useful class constructor functions. [See J&K pages 63-64]

5. Overloaded function names: You can write many different functions with the same name, provided the
argument typ es are differen t and the com piler can tell the d ifference:

int abs(int); // called if the arg is an int.


double abs(double); // called if the arg is double.
You can not overload functions if the only difference is in the return value. [See J&K pages 64-70]

6. Overloaded operators: W e can define new mean ings for operators:


class complex {
public:
float re, im;
friend complex operator+(
const complex &a, const complex &b
);
...
}

complex operator+(
const complex &a, const complex &b
) {
complex z;
z.re = a.re + b.re; // Can use re and im
z.im = a.im + b.im;
return z;
}
Now we can write:

complex a, b, c;

2.5
csc2402 — Object-Oriented Programming in C++ Study Guide

...
c = a + b;
new and delete operators: These are a safer version of the malloc and free functions in C. You should
7.
never use the C functions in C++. [See J&K pages 70-73]
8. Data declarations: You can declare variables anywhere in a block (not just at the start). You can use the name
of a struct or class as soon as its definition is started. Therefore the following works in C+ + but not in
C:

struct list {
void *info;
list *next;
};

[See J&K page 43]

9. Templates: These ar e a major feature of C+ +, respons ible for vastly increased ease of programming compared
with C. We shall devote a complete module to them later.
10. Strings: C++ has a library string class that allows input, output, concatenation, and many common string
operations without having to worry about character arrays, sizes, nul-terminators, and all the other painful stu ff
that makes string processing such a nuisance in C. [See J&K section 2.5]
11. Standard header files: Standard C++ has a new system for #include files that does not have the normal ".h"
ending used in C. For e xample, to use the new standard string package, one writes:
#include <string>

12. Namespac es: Standard C++ allows you to collect names in a namespace. This avoids having lots of global
names all getting mixed up with each other. We shall not need to create any in this course, but the standard
libraries all put their names in namespace std. Therefore many programs will contain the line:

using namespace std;

[See J&K section 2.1]

13. “Stream” input-output: C++ has a new I-O system lacking in C: streams. This comes in two flavours, the one
used prior to the new C++ standard (<iostream.h>) and the standard one (<iostream>). (Use the
standard one.) Som e examp les are shown in the examples below. The old C <stdio.h> system is still there, but
is less safe (although sometimes more convenient). The two should not be mixed. [See J&K section 2.2]
14. File streams: The stream i-o system can, of course, be used on files. [See J&K section 2.3]
15. A Boolea n type: Stand ard C++ has a new da ta type, bool, with constant values true and false. [See J&K
page 40]
16. Exceptions: Standard C++ has a far better way of dealing with runtime errors such as lack of memory, bad
input, numeric overflow, etc., than C or the original C++. This is the exception feature. It is an extre mely
important part of the new language; ho wever, in order to reduce the number of new things you must study right
now, I shall postpone it until later. [But if you’re interested, see J&K section 2.8]

Note About References

Do not re turn a referenc e to a tempo rary variable :

sometype& func(...) {
sometype temp;
...
return temp; // WRONG!!!
}

2.6
csc2402 — Object-Oriented Programming in C++ Study Guide

This is fatal because temp is local to func, and so it disappears when func is exited at the return statement.
This means that the reference (that is, add ress of) temp returned by th e function po ints to unalloca ted memo ry. It
is, of course, alrig ht to return a co py rather than a reference a s follows:

sometype func(...) {
sometype temp;
...
return temp; // OK!!!
}

A good use for reference s would be in overloading the [] operator (so it can function on the LHS of an assignment).

2.5 Examples

Example 1

The example below is a simple illustration of the new standard string class. Notes: The header files must be as
shown (without “.h”). In p articular, <string.h> will not work, as that header is the standard C header containing
strcmp, strcpy, etc. Also see how you can forge t about the size of arrays, etc., with the new string class.

stringdemo.cpp
// Simple example illustrating the use of C++ standard strings.
#include <iostream>
#include <string>
using namespace std;

int main() {
// Example 1: To output "Hello folks! It's a nice day. Bye!"
string s = "Hello folks";
s += "! It's a nice day.";
cout << s << " Bye!\n";

// Example 2: Output "nice day"


cout << s.substr(20, 8) << endl;

// Example 3: To output "Hello folks! It's a GOOD day."


s.replace(20, 4, "GOOD");
cout << s << endl;

// Example 4: To input a line and print it out again.


getline(cin, s);
cout << s << endl;

// Example 5: To input a single word and print it out again.


cin >> s;
cout << s << endl;
return 0;
}

2.7
csc2402 — Object-Oriented Programming in C++ Study Guide

Example 2

The next example illustrates default arguments and simple output formatting using the C++ stream feature . This is
much safer (b ut a bit more o f a pain) than the old C stdio input-output.

miscCppdemo.cpp
// Simple example illustrating:
// Some simple "stream-style" I-O
// Default function arguments

#include <iostream>
using namespace std;

// These arguments have default values of 100 for height and 50 for width.

void setup(int height=100, int width=50) {


// Output here is done using "stream-style" output to the standard
// output stream, cout. We may mix data types, which are converted
// to text. Here we output string literals, ints, and endl (which
// outputs a newline).
cout << "Height: " << height << "; width: " << width << endl;
}

// Se can have defaults for part of an argument list, but as soon as


// one argument has a default, all following arguments must too.
void somedefaults(int a, float b, char c = 'X', double d = 123.698) {
cout << a << " " << b << " " << c << " " << d << endl;
}

int main() {
// Illustrations of default argument values.
// All of the following print: Height: 100; width: 50
setup(); // Both args use default values.
setup(100); // Last arg uses default value.
setup(100,50); // Neither arg uses default value.

// The following prints: Height: 25; width: 50


setup(25);

// The following prints: Height: 25; width: 44


setup(25,44);

// Because somedefaults has no defaults for a or b, we MUST


// provide at least the first two arguments.
// The following prints: 3 2.1 Q 123.698
somedefaults(3, 2.1, 'Q');
return 0;
}

Example 3

The next example illustrates how a reference argument allows alteration of the actual parameter, whereas a value
argument d oes not.

2.8
csc2402 — Object-Oriented Programming in C++ Study Guide

refdemo.cpp
// Simple example illustrating passing arguments by reference.

#include <iostream>
using namespace std;

// A function given an argument by value - that is, a copy:


void alter_copy(int n) {
n++;
}

// A function given an argument by reference to the original:


void alter_reference(int& n) {
n++;
}

// A function given an argument as a pointer to the original.


// Works like a reference, but is much uglier:
void alter_pointer(int *n) {
(*n)++;
}

int main() {
int i=5, j=8, k=3;
alter_copy(i);
alter_reference(j);
alter_pointer(&k);

// the following will output: 5 9 4


cout << i << " " << j << " " << k << endl;
return 0;
}

2.6 Activity

Study
The m aterial discu ssed a bove is c overed in Chapte r 2 in the text, Object-Oriented
Programming in C++, by J&K. Make sure you study that chapter except for “C asts ” in
section 2.4, and exception-handling in section 2.8.

2.9
csc2402 — Object-Oriented Programming in C++ Study Guide

2.7 Exercises

1 Explain exactly why the following program is not legal C (2 problems), yet is legal C++. For C++, predict
the output.

#include <stdio.h>

int main() {
const int c=3;
int a[c];
a[0] = a[1] = a[c-1] = 2;
int i;
for (i=0;i<c;i++) {
printf("%d\n", a[i]);
}
return 0;
}
If the following prototype occurred in a C program, what would you know about the function fred?
2

int fred();

If the same line occurred in a C++ program, what would you know?

3 Is it legal to #include a standard C library header file in a C++ program?

4 Why is it better to use an inline function than a #define statement?

5 (C revision) Write C statements or declarations for the following:

a A declaration (function heading) for a function called joe with one pointer to int parameter and
one float parameter, returning a double.

b A declaration (function heading) for a function called jill with no arguments, returning a
pointer to a double.

c A declaration for a pointer variable called fred that could point to a function such as joe,
described in (a) above.

d A statement that makes fred (see (c) above) point to joe (see (a) above).

e A declaration for a variable called arr that is a pointer capable of pointing to ten ints.

f A statement that makes arr actually point to ten ints.

g (Assume i and k are ints.) The shortest statement you can think of that ma kes i equal to 1 if
k equals 7, and equal to zero otherwise.

h A statement containing no if statement nor conditional op erator, which sets k to 6 if i equals 2,


and sets k to 4 otherwise.

6 (C revision) W hat is the outpu t of the following C co de fragme nts? (Assum e that stdio.h has been
included.)

2.10
csc2402 — Object-Oriented Programming in C++ Study Guide

a { int i = 7; printf("%d\n", i == 7); }

b { int i = 7; printf("%d\n", i == 2); }

c { int i = 3; printf("%d\n", i << 2); }

d { int a[2] = {3, 7}; printf("%d\n", *(a+1)); }

e { int a[2] = {3, 7}; printf("%d\n", a[1]); }

f { int a[2] = {3, 7}; printf("%d\n", *a+1); }

g { int a[2] = {3, 7}, *p = a; printf("%d\n", * ++p); }

h { int a[2] = {3, 7}, *p = a; printf("%d\n", ++ *p); }

7 Using a reference type, write a function called fact with one long argument, wh ose purp ose is to replace
the current value of its argument variable with the factorial of its value. That is, if its argument had the value
3, it would be replaced with 6 (which is 3 ×2×1 ). Thus, the state ments:

long f=4;

fact(f);

cout << f;

would prin t the value 24 .

8 Write a program that reads in lines, each containing a person’s name in “firstname lastnane” format, and
prints each name out in “lastname comma firstname” format. For example, for the input line

Fred Bloggs

the program should print

Bloggs, Fred

Your program should repeat until no more names are found. Use the new standard strings to manipulate the
names.

Summative Practical Exercises


W ork ex ercises 7 and 8 a bove. Reminder: These are compulsory and earn marks
towards yo ur final result.

2.11
csc2402 — Object-Oriented Programming in C++ Study Guide

2.12
Object-Oriented Programming in C++

Module

Standard I-O in C++

3
Written by Ron House
csc2402 — Object-Oriented Programming in C++ Study Guide

3.1 Introduction

The C++ standard input-output classes provide a new way of handling input-output that avoids many of the problems
of input-output in C. Most significantly, C input-output is type-unsafe: that is, it is possible to write statements that
cause the co mpiler to em it bad cod e. For exam ple, try this:

#include <stdio.h>
main () {
printf("1.789 is %d\n", 1.789);
}

The new C++ input-output style is based on classes. It is still pos sible to use stdio -style input-outpu t in C++. In fac t,
some writers think that the C+ + style has its own disadvanta ges that outwe igh the bene fits, and these pe ople quite
deliberately continue using stdio in their C++. That is a matter which you can judge for yourself after you have tried
both methods, b ut, so that you become fully conversant with the new C++ input-output, the old C-style input-output
is completely banned in this course unless otherwise stated for some particular reason.

3.2 The Two Versions of C++ I-O

The C++ standard (as describ ed earlier) ha s many impr ovements over C++ practice for the preceding decade or so.
The input-output system is one area where substantial alterations were made. At the time of writing, the Gnu C++
compilers (both the Linux and DJGPP versions) do not implement the full standard versions of the IO libraries.
However there is a “standard” package available, eve n though it is still incomplete. It is possible to use either version
in a C++ program. Generally speaking, the earlier (non-standard) version of any header file has “.h” at the end of
its name. Therefore, to use the old C++ stream library, one would type:

#include <iostream.h>

The new standard header files do not have a “.h”; therefore, to obtain the equivalent header from the new standard
system, one types:

#include <iostream>

Troubleshooting:

The differences b etween these two systems, ad ded to the fac t that the new system is still not completely consistent
with the standard, mean there are a few minor glitches in using these headers. One problem I have noticed is that the
standard has a class called basic_ios. This still doesn’t have the correct name at the time of writing, so if you get
a sysntax erro r, try using the old n ame: ios.

3.2
csc2402 — Object-Oriented Programming in C++ Study Guide

3.3 Input-output Concepts

The basic i-o library centres around a class called iostream. The main header file is <iostream>. (Some re ally,
really old C++ programs use the header <stream.h>. You are not likely to run into this one.)

General principle: An applic ations prog rammer sh ould not ne ed to know all abo ut the innards o f a class in order
to use it in their pro grams. This principle is true about iostream.

Standard streams provided for all programs include cin cout cerr clog.

These may be compared to the C (stdio) standard FILEs as follows: cin works like stdin, cout like stdout,
and cerr like stderr. clog is meant for log ging opera tions (a reco rd of a pro gram's oper ations).

Why streams as classes?

1 The facilities ar e integrated, ra ther than a who le lot of separa te functions.

2 The compiler `knows what's going on', so it can check the sanity of the various operations better than C can
with <stdio.h>.

3 You can derive your own specialised classes from the ones provided. (Only likely in very advanced
program s.)

3.4 Using iostreams

The first step is to :

#include <iostream>

Then, mostly, use >> to input data and << to output data. These are the old C left-shift and right-shift operators,
being re-used for a n ew purpo se. (C++ allows you to program your own versions of operators.) The standard C++
IO library programs these operators to do input when an istream is on the left o f >>, and output when an
ostream is on the left of <<.

Note: The compiler knows what sort of da ta is being hand led by >> and <<, and compiles appropriate code. That
is, you don't have to tell it as you do with scanf and printf in C when you use format specifiers (%d, %s etc.).
E.g.

#include <iostream>
int ivar; float fvar;
cin >> ivar; // inputs an int.
cin >> fvar; // inputs a float.
cout << "Here are your numbers:\n"; // Outputs a string
cout << fvar; // Outputs a float.
cout << ivar; // Outputs an int.

Note: The direction of the arrow (<< left, >> right) shows the direction o f data move ment. Yo u can conc atenate
operato rs in one statem ent:

3.3
csc2402 — Object-Oriented Programming in C++ Study Guide

cout << fvar << ivar;

[This wor ks for the same reason you can conca tenate multiple a rithmetic op erations in on e statement:

a = b + c + d + e;

If you don't understand this remark, you should immediately study up on the use of operators in C and C++. You
should have learned this material in previous courses.]

Example from text:

cout << prompt << flush;

cout should be flushed automatically due to its special status, so flush should not be needed.

Note: << and >> are operators, just like + and -. Therefore they will operate on any item that has the correct type.
E.g.:

cout << 2.5 * sin(x);

will output a float.

Meaning o f <<:

These are overloaded operators declared in the ostream class. E.g.:

ostream& operator<<( signed char);


ostream& operator<<(unsigned char);
ostream& operator<<( signed int);
ostream& operator<<(unsigned int);
ostream& operator<<(float);
ostream& operator<<(double);
...

Their first argument is the class objec t on the left-hand side, and the o perators re turn this objec t as their result.
Therefo re, a multiple o utput is parsed like this:

cout << "Answer is " << x + 1.25;


.23- /2222222222- /222222-
.)) << )- *
* *
cout *
.))))))))))))))))<< -
*
cout

3.4
csc2402 — Object-Oriented Programming in C++ Study Guide

3.5 Manipulators

These a re items that can be placed in a list of << or >> to change the behaviou r of the stream. E .g.:

dec (decimal) E.g. cout << dec << ivar;


cin >> dec >> ivar;

hex (hex) E.g. cout << hex << ivar;


cin >> hex >> ivar;

oct (octal) E.g. cout << oct << ivar;


cin >> oct >> ivar;

ws (skip whitespace) E.g. cin >> ws;

endl (newline & flush) E.g. cout << endl;

ends (output nul) E.g. cout << ends;

flush (flush output) E.g. cout << flush;

Note: To mix iostream inp ut-output with C's FILE-style input-output, c all the function:

basic_ios::sync_with_stdio();

By the way, d on’t forget the w arning earlier: if basic_ios doesn’t wo rk on your syste m, try ios instead.

3.6 Formatting

Formatting is, in my opinion, much clumsier in the C++ class method than in C's stdio. Against that we have to
balance the fact that it is much safe r. Use man ipulators: dec, oct, hex, etc.

Note: You mu st #include <iomanip>.

For equiv alent of:

printf("%6.2f", fvar);

use manipulators setprecision and setw:

cout << setw(6) << setprecision(2) << fvar;

These re set to the defau lt values after eve ry output op eration.

See also setbase and setfill.

3.5
csc2402 — Object-Oriented Programming in C++ Study Guide

3.7 Format Flags

These alter the appearance of the output or the behaviour of the input. Set with setiosflags and reset by
resetiosflags. For exam ple:

cout << setiosflags(ios_base::scientific);

causes the system to output in scientific notation. For example:

#include <iostream.h>
#include <iomanip.h>

main () {
float fvar = 2.6;
int ivar = 7;
cout << setw(12)
<< setprecision(2)
<< setiosflags(ios_base::fixed)
<< fvar
<< ";" << ivar << ";"
<< fvar << ";Hi";
return 0;
}

Outputs:

2.6 ;7;2.6;Hi

Things that can be set with setiosflags:

Name Purpose

ios_base::skipws Skips whitespace

ios_base::left left-justify

ios_base::right right-justify

ios_base::scientific Use scientific notation

ios_base::fixed Use fixed notation

ios_base::dec Use decimal notation

ios_base::oct Use octal notation

ios_base::hex Use hexadecimal notation

ios_base::uppercase Use upper case letters in nos.

ios_base::showbase Prefix 0x for hex & 0 for octal

ios_base::showpoint Always put d ecimal po int in floats

ios_base::showpos Put + sign on positive nos.

3.6
csc2402 — Object-Oriented Programming in C++ Study Guide

As before, if your compiler won’t let you have ios_base , try plain old ios.

3.8 Overloading <<

It is straightforward to make << work for new classes you write yourself. Write a new operator<< for the class
concerned, as follows:

overloadout.cpp
#include <iostream>
#include <iomanip>

class complex {
float re, im;
public:
float real() const {
return re;
}
float imag() const {
return im;
}
complex(float a = 0, float b = 0) {
re = a; im = b;
}
};

ostream& operator<< (ostream &s, const complex& z) {


s << z.real() << " + " << z.imag() << "i";
return s;
}

main () {
complex a(1.5, 2.1);
cout << setiosflags(ios::scientific)
<< a << endl;
cout << setiosflags(ios::fixed)
<< a << endl;
return 0;
}

This Prin ts:

1.500000e+00+2.100000e+00i
1.5+2.1i

3.7
csc2402 — Object-Oriented Programming in C++ Study Guide

3.9 Overloading >>

Like <<, >> is also fairly easy to overload for your own new classes. This is just a bit harder for >> than for <<.
[overloadin.cpp]

Simplified version:
class complex {
//... as before ...
};

istream& operator >> (istream &s, complex &z) {


float re, im;
s >> re >> im;
z = complex(re, im);
return s;
}

main () {
complex a;
cout << "Enter complex: ";
cin >> a;
cout << setiosflags(ios::fixed)
<< a << endl;
return 0;
}

The pro gram runs a s follows:

Enter complex: 34 78
34+78i

3.10 File Input-Output

This is obtained from classes ifstream, ofstream, and fstream. You mu st #include <fstream> in
program s that do file inpu t-output. W e can dec lare a stream a nd open a file at once:

main(int argc, char *argv[]) {


ifstream inf(argv[1]);
if (!inf) {
cout << "Input file error\n";
}
...

We ca n close it at will:

inf.close();

Or we can let the destructor do it automatically when the stream variable is destroyed.

3.8
csc2402 — Object-Oriented Programming in C++ Study Guide

End of file:

There are ‘state bits’ associated with each stream that tell whe ther any error has been e ncountere d, or if end o f file
has been reached, etc. But for simple programs, the stream itself can be used as a condition:

if (cin) {
// cin has not yet hit end of file.
}

3.11 Exercises

1 If you can, predict the output from the following C++ code fragments. (Assume iostream and iomanip
have been included.) (Warning: one of the following has unpredictable output according to the C++
standard - sa y which one it is, an d predict its o utput on a 32 -bit compu ter.)

a { int i = 4; cout << (i == 8, 2) << " " << i << endl; }

b { int i = 4; cout << (i = 8, i == 4) << endl; }

c { int i = 4; cout << setw(4) << (i = 8, i == 4) << endl; }

d { int x[4]; cout << sizeof x/sizeof(int) << endl; }

e { int x[4]; cout << sizeof x/sizeof(int) << endl; }

f { const char *p = "Hello\n"; cout << sizeof p << endl; }

g { const char p[] = "Hello\n"; cout << sizeof p << endl; }

2 Write a C ++ pro gram to pr oduce the following outp ut:

+------
|*
| *
| *
| *
| *
| *

3 Program as many exercises from J&K chapter 2 as you have time for.

4 Write a program to print all ASCII characters in the range ‘ ’ (spa ce) to ‘~’ along with their corresponding
code values in both decimal and he xadecimal. These sho uld be nicely formatted in colum ns with headings.

5 Write a comple te program to read a file of floating point numbers, make complex numbers out of the
successive pairs of numbers read, and write them out in complex notation. Develop your own comp lex class
based on that in the lectures or the textbo ok in order to do this.

3.9
csc2402 — Object-Oriented Programming in C++ Study Guide

Summative Practical Exercises


Work exercises 4 and 5 above.

3.10
Object-Oriented Programming in C++

Module

Classes and Abstract

4
Data Types

Written by Ron House


csc2402 — Object-Oriented Programming in C++ Study Guide

4.1 Introduction

The class is the most important new feature of C++. It’s main use is to support object-oriented
programming, but it is not limited to that. In this module, we look at both the class C++ language
construct and its features, and also its use in OO programming to implement the first of the three main OO
concepts, namely information hiding (also called encapsulation) an d abstract data types.

Some background considerations

W e are consid ering obje cts and types in this course. One way to look at this is to consider an object as the primary
concep t, and derive the idea of a typ e (i.e. a class) from it. T he other po ssibility is to consider a type as the primary
concep t, and consid er objec ts as examp les of the type.

One view: O bject ! Type

Definition: An object is an entity that

- has a state that persists for a period,

- has an interface: a set of methods (com mands, queries) to which it respon ds,

- hides inform ation: you can only modify the state by invoking a method .

Definition: A type is the set of all objects in a system that respond in the same m anner to the same messag es.

Alternative: Type ! Object

Definition: A type is a (possible) set of values (tha t an object o f the type might have) together with a set of
operation s on those (p ossible) value s. The set o f operations is th e public interfa ce.

Definition: An object is a holder for a (possibly changeable) value of a single type. The state of an object is its
current value. Objects are called instances of their type.

Philosophy:

The latter set of definitions (type ! object) encourag es program ming by de signing types an d then crea ting objects
of those types. (For example C++: design classes, then declare variables belonging to those classes.)

The former set of definitions (ob ject ! type) encourages the creation of objects and the extraction of types that many
objects have in common. (Such types might not all have the same implementation.) Even types can be considered
to be objects in this view (for example Smalltalk). Personally, I don't like Smalltalk; its lack of static (i.e. compile-
time) type checking is a serious bligh t. Smalltalk only o bjects to typing errors or m issing method s when you try to
execute the method at runtime. As Bertrand Meyer, the designer of Eiffel, once remarked during a sem inar : “I d on't
want to be a passenger on an airpla ne about to land, and find that the programmer forgot to write the `lower-landing-
gear' method!” In this regard, statically-typed languages like Eiffel and C++ are definitely superior.

Our purpose in discussing thes e issues is to remember that OO prog rams should implem ent classes as abstract d ata
types.

4.2
csc2402 — Object-Oriented Programming in C++ Study Guide

Definition: An abstract d ata type is a type defined in terms of the operations that may be performed on
the type’s objects (not in terms of the ways in which these operations are implemented or the data fields
necessary to support the operations).

For example, we may think of an int as an abstract data type if we define it in terms of permitted operations (such
as addition, sub traction, input, o utput, etc.) and not in terms of im plementatio n (for example, twos-complement
binary 32-bit number).

4.2 C++ Class Features

Study
The material discussed above is covered in Chapter 3, sections 3.1 through 3.4, and
parts of s ection 3.5 in the text, Object-Oriented Programming in C++, by J&K. Make
sure you study that chapter as you proceed through these notes.

The main C++ object-oriented feature is the class. A class is similar to C's struct. In C, a struct can only
contain data, but in C++, a struct or a class can contain both data and functions. Also, in C++, data and
functions can have their accessibility restricted with the keywords public, private, or protected. A public
field is one that can be accessed anywhere that the class as a whole can be accessed. A private field can only be
accessed within the class itself. (We’ll leave protected for later.)

The only difference between a struct and a class is that in a struct, all fields are by de fault public, whereas
in a class they are by de fault private. Fo r example , the following are identical:

struct Person { class Person {


string name; public:
int age; string name;
}; int age;
};

Question: What sort of functions would we add to a class?

Answer: Functions that perform all the operations of an Abstract Data Type.

In OO terminology, a function that is part of a class is called a method.

What does it mean to say that a function is part of a class? To answer this, think first what we mean when we say that
a data field is part of a struct. Simply put, it means that every variable declared to be of that structured type has
its own private copy of that d ata field. For example, given the class or struct Person as shown above, if we
now write:

Person p1, p2;

then p1 has name and age fields, and p2 also has its own separate name and age fields. Let us now give the class
a field that is a function (i.e. a method):

4.3
csc2402 — Object-Oriented Programming in C++ Study Guide

class Person {
public:
string name;
int age;
void output() { cout << name << " " << age << endl; }
};

Here we have written an output method w hose purp ose is to display the name and age fields. Even though the
compiler doesn’t actually implement it this way, to understand what is going on here we must imagine that every
object in the class has its own separate output function, just as each one has its own separate name and age fields.
We can ac cess the data fields in a specific object as follows:

p1.name = "Fred"; p1.age = 25;


p2.name = "Mary"; p2.age = 23;

Likewise, we c an call the functio n belonging to a particular o bject:

p1.output();
p2.output();

This will disp lay:

Fred 25
Mary 23

In short, the code within a method, when it uses the names of other fields in the class, accesses the particular copy
of those fields that reside within its owning object. [The above code segments are from program
persondemo.cpp.]

Study
Chapter 3 (Classes) in J&K contains more explanation and examples. Study J&K
sections 3.1 through 3.4 now. (Pages 99-123)

4.3 Example: Design a Class Describing a Person

What operations are required? W hen designing an abstract data type (ADT), we should think in terms of the
operation s that may be p erformed on that data typ e, not in terms of how we store the data.

Possibilities:

Input person data,


Output person data,
Setting and querying:
name
age
address.

Refine:

4.4
csc2402 — Object-Oriented Programming in C++ Study Guide

I-O is often problem dependent, and might change if the ap plication is altere d. There are prob lems with
input-output for such a vague thing as a person. Therefore, any input-output fun ctions defined will probab ly
not satisfy all requirements in all programs. However, in setting and querying the name and age , there is
no prob lem.

Addresses have very va riable forma ts: for flexibility, let's have functions to set and query the number of
address line s, then functions to set and que ry each line indiv idually.

Possible definition of th e class:

[Program classperson.cpp]
#define MAX_LINES 3

class Person {
public:
const char* name();
void set_name(const string&);
int age();
void set_age(int);
int num_address_lines();
int set_num_address_lines(int);
const char* address_line(int);
int set_address_line(int, const string&);
int input();
void output();
private:
int num_addr_lines;
string name_buf;
int age_val;
string addr_lines[MAX_LINES];
};

public means that the world can access these ite ms. private means that o nly class members can access. The
public members must be properly specified in order to be useful. In object-oriented programming, it is common
to hide all data membe rs as private. public functions are p rovided to handle all accesses and modifications.
This allows class designe rs flexibility in changin g the `innards' of a cla ss without chan ging the pub lic interface.

Specification of public methods:

It is important to document the intended p urpose o f all functions before actually programming them. Most beginners
(most experts?) put off documentation until after the functions are written. This is a major mistake. After all, what
would you think of an eng ineer who b uilt a bridge b efore makin g a plan? If yo u don't know what a function is
supposed to do, how can you pro gram it? T he idea of cla ss docume ntation is to pro vide a firewall between the class
implementation and the users of the class; neither group should have to look at program code from the other group
to find bugs. T herefore the function definitio ns should b e exhaustive a nd precise .

One way to write good function documentation is to focus o n two specific questions: what must be done or set up
so that this function can work properly? and then If those things have been set up, what does this function guarantee
to do for the caller? The first is called a precondition and the second a postcondition. Therefore, when writing
specifications, don 't waste anyone's time telling them trivia about the internals, such as that the function uses a for
loop or a n array, or suc h like; stick to the req uirements (p reconditio n) and the un dertaking (p ostconditio n).

With these ideas in mind, we might write the specifications as follows:

4.5
csc2402 — Object-Oriented Programming in C++ Study Guide

[Program classperson.cpp]
////// name:
// Returns a pointer to the person's name.
////// set_name(str):
// Sets the person's name to str.
////// age:
// Returns the person's age
////// set_age(a):
// Sets the person's age to a.
////// num_address_lines:
// Returns the no. of lines in person's address.
////// set_num_address_lines(a):
// If a is not too large, sets the number of
// address lines in the person's address to a,
// otherwise sets it to the closest legal
// value to a. Returns the number of address
// lines actually allocated.

////// address_line(n):
// Returns a pointer to address line n (n>=1) of
// a person's address. If n is out of range,
// returns a pointer to an empty string.
////// set_address_line(n, str):
// If n is the number of a legitimate address
// line, sets address line n to str, and returns
// 0. Otherwise, returns 1.
////// input:
// Asks user for each field. For address lines,
// accepts lines until user enters a blank line
// or the maximum no. of lines have been input.
// Returns 0 on success, EOF on end-of-file.
////// output:
// Displays each field preceded by a descriptor
// tag.

If we have de fined the cla ss well enough, we should be able to use it in a program without seeing the code that
implemen ts the method s. With this in m ind, here is a p rogram tha t uses the class to re verse a list of Persons:

[Program classperson.cpp]
#include <iostream>
#include <string>
using namespace std;

int main() {
Person p[20];
int count;

for (count=0; count<50 && p[count].input() != EOF; count++) {


// Keep going
}
cout << endl;

// Output people in reverse order: (Why not?)


while (count > 0) {
count--;
p[count].output();
cout << '\n'; // Extra newline

4.6
csc2402 — Object-Oriented Programming in C++ Study Guide

}
return 0;
}

Now let's write the method fun ctions. W e can still use the stand ard C libra ry functions to he lp out.

Writing a class method fun ction is just like writing a normal function, except that we must `scope' the function
by telling the compiler which class it belongs to.

const char* Person :: name() {


// ^^^^^^^^^ Class for this function
return name_buf.c_str();
// ^^^^^^^^ You can access the private
// members if necessary
}

Each func tion will be written sim ilarly.

[Program classperson.cpp]
const char* Person :: name() {
return name_buf.c_str();
}

void Person :: set_name(const string& nam) {


name_buf = nam;
}

int Person :: age() {


return age_val;
}

void Person :: set_age(int age) {


age_val = age;
}

int Person :: num_address_lines() {


return num_addr_lines;
}

int Person :: set_num_address_lines(int lines) {


if (lines < 0) {
num_addr_lines = 0;
} else if (lines > MAX_LINES) {
num_addr_lines = MAX_LINES;
} else {
num_addr_lines = lines;
}
return num_addr_lines;
}

const char* Person :: address_line(int lin) {


assert(num_addr_lines >= 0 && num_addr_lines <=MAX_LINES);
if (lin > 0 && lin <= num_addr_lines) {
return addr_lines[lin-1].c_str();
} else {
return "";
}
}

int Person :: set_address_line(int lin, const string& addrln) {


assert(num_addr_lines >= 0 && num_addr_lines <= MAX_LINES);
if (lin > 0 && lin <= num_addr_lines) {

4.7
csc2402 — Object-Oriented Programming in C++ Study Guide

addr_lines[lin-1] = addrln;
return 0;
} else {
return 1;
}
}

int Person :: input() {


string buf;
char c;

if ( ! cin) { // If stream not OK, return EOF immediately.


return EOF;
}

// We can use our publ ic functions:


cout << "Name? ";
getline(cin, buf, '\n'); // Safe loading into array.
if ( ! cin || buf == "") {
return EOF;
}
set_name(buf); // Using public function

// Or, in member functions, we can directly access


// the private members themselves.
cout << "Age? ";
cin >> age_val;
while (cin.get(c) && c != '\n') {
// Toss out extra chars until end of line
}

int count = 0;
num_addr_lines = 0;
while (set_num_address_lines(num_addr_lines+1) > count) {
// Have allocated another address line
cout << "Address " << num_addr_lines << "? ";
if (getline(cin, buf, '\n'), !cin || buf == "") {
num_addr_lines--; // Don't count this one.
break; // Exit from while loop
}
count++;
set_address_line(num_addr_lines, buf);
}
return 0;
}

void Person :: output() {


cout << "Name: " << name() << '\n';
cout << "Age: " << age() << '\n';
int count, numlins;
numlins = num_address_lines();
for (count = 1; count <= numlins; count++) {
cout << "Address " << count << ": "
<< address_line(count) << '\n';
}
}

4.8
csc2402 — Object-Oriented Programming in C++ Study Guide

4.4 Constructors and Destructors

W e can automatically initialise an object by prov iding a constructor in the class definition. We can also
automatica lly `tidy up' and `close down' an object when it is deallocated by providing a destructor in the
class definition.

For example, to automatically set the fields of a Person to sensible (i.e. empty) values, add to class Person:

class Person {
public:
Person(); // Declaration for the constructor function
...etc.

Then write the constructor function:

Person :: Person() {
cout << "In Person\n"; // For testing only
num_addr_lines = 0;
name_buf ="";
age_val = 0;
}

These are called automatically when variables are declared.

Study
Study all of section 3.5 (pages 124 to 128 and the topic "The Destructor" on pages 139
through 141) of J&K now.

The thing to remember about constructors is that we are providing a class with a complete set of facilities for creating
objects in useful ways. The main purp ose of destru ctors is to ensure that objects are finalised properly: for example,
releasing dyn amic mem ory.

4.5 Summary

Think of a class as a kind of data type (like int, float, etc.). When you write a class, such as Person, you are
adding a new data typ e to the langau ge. The o perations yo u provide for that type can then be used in the same
manner as operations for built-in types. There are some differences in C++ between built-in types and classes, but
as a general rule they work similarly. (One significant difference is that you cannot inherit from built-in types, but
more of tha t later.)

4.9
csc2402 — Object-Oriented Programming in C++ Study Guide

4.6 Example

This example is another take on the concepts discussed in the text. Make sure you have read the material from the
text as mentione d above before pr oceeding . Our purp ose is to show that a class should be an abstract data type;
that is, we should be able to use it without knowing anything about how it is implemented internally. Therefore we
shall write two different versions of the class, one using an array, and the other u sing a linked list, bu t both
performing exactly the same task.

Problem: Suppo se we need a stack of nam es in a progr am.

Solution: Design a ge neral-purp ose stack cla ss. This will use an array to hold the stack elemen ts. Each elem ent will
be a void pointer to the user's data item.

W e first need to define a header file for the class. This is the interface between the class and the programs that use
the class.

stackarr.h:
#ifndef __STACKARR_H__
#define __STACKARR_H__

class stack {
int size, sp; // Maximum and current size
void **items; // Pointer to array of void pointers

public:
/**** stack: Constructor ******
On entry: size is the maximum number of elements to be stored
in stack.
On exit: Sets up a correctly initialised empty stack.
*/
stack (int /*size*/ = 50);

/**** ~stack: Destructor ******


On exit: Any space used by stack (but not space used
by the calling application program) has been freed.
*/
~stack();

/**** stack_push: ******


On entry: item points to an item to be added to the stack.
On exit: If item has been added to the top of the stack,
returns 1, If addition failed, returns 0.
*/
int stack_push(void * /*item*/);

/**** stack_empty: ******


On exit: Returns 1 if stack empty, else 0
*/
int stack_empty();

/**** stack_pop: ******


On exit: If stack not empty, returns top item and removes it
from stk, otherwise returns NULL.
*/
void *stack_pop();

/**** stack_top: ******

4.10
csc2402 — Object-Oriented Programming in C++ Study Guide

On exit: If stack not empty, returns top item (not removed from
stk),otherwise returns NULL.
*/
void *stack_top();

/**** stack_count: ******


On exit: Returns count of number of items in the stack.
*/
int stack_count();
};

#endif

The above functions should be sufficient to allow reasonably conve nient use of a stack. Now we need a connector
file. (The pu rpose of this w ill be seen later.):

stackarraydemo1.cpp:
#define STACKDEFINITIONFILE "stackarr.h"
#include "stackdemo1.cpp" // This file is shown later

Now to program the stack class; this will be in its ow n source file:

stackarr.cpp:
// Array-based implementation of the ADT stack.

#include "stackarr.h"
#include <stdlib.h>
#include <iostream>

using namespace std;

stack :: stack(int siz) {


// Try for the array of void pointers
cout << "Constructor: setting up for size="
<< siz << endl;
items = new void* [siz]; // "new" array notation
if (items == NULL) { // no space for array?
cerr << "Failed to get space\n";
exit(EXIT_FAILURE);
}

// Set up housekeeping fields of stack.


size = siz; // Maximum size
sp = 0; // Stack starts out empty
return; // initialised stack
}

stack :: ~stack() {
delete [] items; // Free array of pointers
}

int stack :: stack_push(void *item) {


// Detect overflow by checking size limit.
cout << "Pushing (sp=" << sp
<< ") (size=" << size << ")\n";
if (sp >= size) {
return 0; // fail
}
items[sp] = item; // Record address in array
sp++; // Count it.

4.11
csc2402 — Object-Oriented Programming in C++ Study Guide

return 1; // succeed
}

int stack :: stack_empty() {


return (sp == 0); // If true, stack is empty
}

void *stack :: stack_pop() {


void *item;
if (stack_empty()) { // Check for item on stack
return NULL;
}
item = stack_top(); // Get top item.
sp--; // Pop it from stack
return item;
}

void *stack :: stack_top() {


if (stack_empty()) { // Check for item on stack
return NULL;
}
return items[sp-1]; // Return data address
}

int stack :: stack_count() {


return sp;
}

Now the stack package can be used for creating stacks in program s, such as the follo wing:

stackdemo1.cpp
// Program to reverse a list of names using the stack package

#include <iostream>
using namespace std;

#include <stdlib.h>
#include <string.h>

// This file will not be compiled directly, but only by inclusion


// in a file that predefines STACKDEFINITIONFILE.
#include STACKDEFINITIONFILE

void fatal(char message[]);


int can_load_name(stack &stk);
void unload_name(stack &stk);

int main() {
stack s(100); // Declare stack variable
cout << "Enter names:\n";
while (can_load_name(s)) {
// Try again
}
cout << "Names are:\n";

// All names loaded; now unload and output.


while (! s.stack_empty()) { // Still more?
unload_name(s); // yes - pop and print
}
return 0; // Destructor called here for s.
}

4.12
csc2402 — Object-Oriented Programming in C++ Study Guide

// fatal: print error and stop


void fatal(char message[]) {
cerr << "ERROR:" << message << "!\n";
exit(EXIT_FAILURE);
}

// can_load_name: Read a name & push; return 1


// (success), or 0 (fail)
int can_load_name(stack &s) {
char buf[80], *nam; // Temporary buffer,
// and pointer for the name
char dud;

if ( ! cin.get(buf, 80, '\n')) {


// Try to read name. Fail?
return 0; // Report failure
}
cin.get(dud); // Input '\n', ready for next name input

nam = new char [80]; // get space


if (nam == NULL) { // fail?
fatal("No space for name");
}

strcpy(nam, buf); // copy string into nam


if (! s.stack_push(nam)) {
// Try pushing buffer's address - fail?
fatal("No room on stack");
}
return 1; // Report success
}

// unload_name: Assumes there is a name in the stack;


// removes & prints it
void unload_name(stack &stk) {
char * buf;
buf = (char*)stk.stack_pop();
cout << buf << endl;
delete [] buf; // Reclaim space new'ed above.
}

Now suppose we decide to re-implement the entire stack package using linked lists. (We might do this if we found,
upon using the stack package, that it did not have the performance we required for some reason — perhap s the use
of the array is too infle xible.) Our previous main program was called stackarraydemo1. This time we shall call
it stacklinkdemo1. We ca n create this ver y simply:

Step 1: Write a new main program. This is easy because all we have to do is change the name of the stack include
file:

stacklinkdemo1.cpp:
#define STACKDEFINITIONFILE "stacklnk.h"
#include "stackdemo1.cpp"

Step 2: Write the n ew class definitio n:

4.13
csc2402 — Object-Oriented Programming in C++ Study Guide

stacklnk.h:
#ifndef __STACKLNK_H__
#define __STACKLNK_H__

//***** stack.h: Definition of the Abstract Data


// Type, stack. *****

class stack {
struct listnode *list;
int itemcount;

public:

// (...as before...comments deleted below for brevity...)

stack (int /*size*/ = 50);


~stack();
int stack_push(void * /*item*/);
int stack_empty();
void *stack_pop();
void *stack_top();
int stack_count();
};

#endif

Step 3: Write the n ew class imp lementation :

stacklnk.cpp:
typedef struct listnode { // type for list items
struct listnode *next;
void *item;
} listnode;

#include <iostream>
using namespace std;
#include "stacklnk.h"

stack :: stack(int) { // Note missing parameter name 1


list = NULL; // No nodes
itemcount = 0; // so count is 0
return;
}

stack :: ~stack() {
listnode *temp;
while ((temp=list) != NULL) {
list = list->next;
delete temp;
}
itemcount = 0;
}

int stack :: stack_push(void *item) {


listnode *p;

1
The omission of a parameter name is allowed in C++ if the parameter will
never be used. This avoids annoying warnings from the compiler about unused
variables.

4.14
csc2402 — Object-Oriented Programming in C++ Study Guide

p = new listnode; // space for list node


if (p == NULL) {
return 0; // no space for node
}
itemcount++; // count extra node
p->item = item; // record user data ptr
p->next = list; // p precedes current
// list
list = p; // and becomes new head
return 1; // success
}

int stack :: stack_empty() {


return itemcount == 0;
}

void *stack :: stack_pop() {


listnode *p;
void *result;
if (list==NULL) {
return NULL; // No node, so no data!
}
itemcount--; // one fewer items
p = list; // address of head node
result = p->item; // recover user's data ptr
list = p->next; // disconnect head node
delete p; // free discarded node
return result; // return user's data ptr
}

void *stack :: stack_top() {


if (list==NULL) {
return NULL; // No node, so no data!
}
return list->item; // return user's data ptr
}

int stack :: stack_count() {


return itemcount;
}

As we might expect, this functions identically to the previous version.

4.7 Exercises

The exercises 1 and 2 should be don e in a fairly sim ple-mind ed way ; don't try to w rite `bullet-p roof' cod e that cou ld
be used in a real setting. Your goal should be to write a `toy' system to demonstrate firstly the `old' style and then
the class style using an abstract data type.

1. In an old C prog ram, a structure is declared as follows:

struct buf {
char *p;
};

4.15
csc2402 — Object-Oriented Programming in C++ Study Guide

It is always used to automatica lly allocate an a rray of char, which may be of different sizes for different
objects. Write a C++ class that has a constructor and destructor; your constructor should take an int
argument to be used as the size of the arr ay. The de structor shou ld reclaim the space used by the array.

2. Yes or no:

a A class constructor cannot be private.

b A class may have pub lic variables.

c A class may have private functions.

d The follo wing is correc t:

class fred {
public:
fred() { p = new int; }
~fred() { free(p); }
int *p;
};

e The follo wing is correc t:

class fred { };

3. A certain glo bal variable , quantity, is set to 0 at the start of function f. At various points in f, it may
be changed to other value s, but when f terminates (for whatever reason!), we want to be sure that
quantity is reset to 0. Write a class called terminator, which will set quantity to 0 at the end of
any block in which an object of type terminator is declared.

4. (Lateral thinking puzzle) Write a program that contains the following main function, exactly as shown
below:

int main() {
cout << "Hello ";
cout << "World\n";
return 0;
}
The pro gram shou ld print the follo wing outpu t:

This is my special
Hello World
program!
(Do no t do this by trying to override the built-in “<<“ op erator. Th ink classes!)

5. Write a class called Tool that holds a single string, namely the name of the tool. It should have a constructor
to create a new object whose name is already filled in, but NO default constructor (so that it should be
impossible to create a Tool without a name). It should have a method, name(), that returns a pointer to a
const null-terminated string (C-style, irrespective of how you store the string internally) containing the tool
name (e.g. "hammer", "spade", etc.) Finally, the class should have a static method that always returns (as
an int) the number of tools that currently exist. Tools that were created but have ceased to exist should not
be counted.

6. (Non-ADT) Write a C-style struct definition for a d ata type called product that can store product
information for a store. Each product has a quantity on hand, price, and part number. Each product can be
sold (in qua ntities up to the q uantity on hand ) or re-orde red. W rite functions that d o these tasks.

4.16
csc2402 — Object-Oriented Programming in C++ Study Guide

The sell function should take as arguments a pointer to a product variable and the quantity to sell, and
returns the num ber actually so ld.

The reorder function takes as arguments a pointer to a product variable and the quantity to be ordered,
and (to keep things simple) merely prints a message saying that whatever number of whatever part must be
ordered. (A `real' version of this function wou ld have to d o more, o f course. Fo r example , it might actually
issue electronic orders.)

Now write a function, ask_user, that takes as an argument a pointer to a product variable, and which
gives the user the opportunity to sell or reorder this produc t.

7. (ADT style) Rewrite your solution to problem 1 as follows: instead of a struct, use a class for the
product, which should have no public data fields, and where the sell and reorder functions are
members of the class. These functions will not need a pointer to a product as an argument because the
fields of the object they belong to can be accessed without further ado within the function. For example,
instead of writing in this style:

int sell(product *p , int number) {


...
p->no_in_stock -= number;
...
}
you can write in this style:

int product :: sell(int number) {


...
no_in_stock -= number;
...
}
Finally, re-write ask_user to use the new class. This sho uld not be a class member. Calls to the new class

member functions will have to be modified. Instead of writing:

sell(&some_product, 35);
you would write:

some_product.sell(35);
As all the class data members are private, you might have to invent some more access functions in the class
if your ask_user function is displa ying produ ct codes, etc .

8. Design a class called histogram that has a constructor which allows the caller to specify the range of
values the histogram will keep track of. The class should have a '+' operator that 'a dds' an integer value to
the histogram and an ov erloaded '<<' operato r for output. Fo r example , the statement

histogram h(1,5);
should create a histogram variable, h, that can store counts of the numbers 1 through 5. Then, the lines:

h+2+3+4+3+2+2+1;
cout << h;
should prin t something like :

1|*
2|***
3|**
4|*

4.17
csc2402 — Object-Oriented Programming in C++ Study Guide

5|
+---
Work as many of the exercises and programming exercises from chapter 3 of J&K as you have time for.
9.

Summative Practical Exercises


Work problems 7 and 8 above.

4.18
Object-Oriented Programming in C++

Module

More on Classes

5
Written by Ron House
csc2402 — Object-Oriented Programming in C++ Study Guide

5.1 Introduction

Study
The C++ material discussed in this module is covered in Chapter 3 sections 3.5 through
3.8 in the tex t, Object-Oriented Programming in C++, by J&K. Make sure you study that
chapter (including any additional material it contains) in parallel with the discussions that
follow.

Some important topics covered in the text are:

Creating and destroying o bjects,

- the various types of constructors,

- member initialisers,

functions and operators,

- this,

- operators new and delete,

Class data members ("static" members).

5.2 Some Assorted Points

Constructors:

* Make a constructor for each expected style of initialisation.

For example a data type Month might be initialised by month nu mber or b y month nam e. Therefo re:

Month(int num);
Month(const char *str);
Make con structors public (otherwise the y can't be used).
*

* Syntax:

C-style: Month when = "Jan";

Function: Month then(8);

5.2
csc2402 — Object-Oriented Programming in C++ Study Guide

Dynamic: Month *m=new Month("Jan");

* Defau lt constructor: This is any constructor with no arguments. Used when no arguments are specified,
or when using new to allocate an array of obj ects.

* Copy co nstructors: A constructor with an argume nt of the same class:

Month (const Month&);


Used when a simple memory copy is not good enough. (For example when pointers are involved, memory
copy doesn't copy what the pointers point at.)

* Mem ber initialiser lists: A construc tor efficiency de vice. For ex ample:

class classA {
...
};

class classB {
classA Avar;
public:
classB(const classA& a) : Avar(a) {
// empty
}
};
Initialiser lists always follow a colon (:) after the constru ctor's parameters. The above replaces the form:

classB(const classA& a) {
Avar = a;
}
These are also useful to initialise const member variables and reference variables (as these cannot be

assigned to) .

* Side effects: classes can be defined purely for the code executed b y their constructors and dest ructors
(without alloca ting storage). See the timer examp le in the text.

The this pointer

Within any class mem ber function , this is a pointer to the class object that the member function belongs to when
it is executed.

For exam ple, to return the object itself from a function:

class classC {
...
public:
classC& memberfunc(...) {
...
return *this;
}
...
};

5.3
csc2402 — Object-Oriented Programming in C++ Study Guide

Type conversion operators

These allow automatic type conversions. For example:

class complex {
float re, im;
public:
complex(float r, float i);
...
};

class double_complex {
double re, im;
public:
operator complex() const {
return complex((float)re, (float)im);
}
...
};

Assignment operator

This cop ies an obje ct onto ano ther that is alread y initialised. It must:

Correctly delete any existing contents of the object being overwritten (for example allocated dynamic
memory),

Protect ag ainst copying something o nto itself,

Return a reference to the object assigned to (for correct multiple assignments).

Example: (stackarr class)


class stack {
int size, sp;
void **items;
public:
stack (int /*size*/ = 50);
~stack();
int stack_push(void * /*item*/);
int stack_empty();
void *stack_pop();
void *stack_top();
int stack_count();

/**** operator = ****


On exit: Existing LHS deleted, new LHS is
copy of RHS, including the array
of pointers.
*/
stack& operator =(const stack& s);
};

5.4
csc2402 — Object-Oriented Programming in C++ Study Guide

And the definition:


stack& stack :: operator =(const stack& s) {
// First operand is this, second is s.
if (this != &s) {
delete [] items; // in this
size = s.size;
sp = s.sp;
items = new void* [size];
if (items == NULL) {
cerr << "Failed to get space\n";
exit(EXIT_FAILURE);
}
for (int i=0; i<sp; i++) {
// Duplicate contents.
items[i] = s.items[i];
}
}
return *this;
}

Test program:
int main() {
stack s1(100), s2(100);
cout << "Enter names:\n";
// Load into s1:
while (can_load_name(s1)) {
// Try again
}
cout << "Names are:\n";
// Copy and then unload from s2:
s2 = s1; // Use of assignment operator.
while (! s2.stack_empty()) {
unload_name(s2);
}
return 0; // Destructor called for s1 & s2.
}

This functions exactly as before!

Overloading new and delete:

This can be do ne for specialised memo ry allocation as follows:

#include <stddef.h>
void * operator new (size_t siz);
void operator delete(void *p);

These definitions can be placed in a class when sp ecial allocatio n is needed only for a par ticular class. If define d in
a class, they are static functions: they belong to the class as a whole and n ot to the particular class objects:
therefore they cann ot access this or any class data members.

5.5
csc2402 — Object-Oriented Programming in C++ Study Guide

Study
Study all of sections 3.5 and 3.6 of J&K now.

5.3 “Static” Data and Methods

Normal data fields and methods in a class are replicated for each object of the class, as we have seen. Therefore, for
such a field or meth od, we can imagine that the re is a copy for every obje ct we create. It is also possible to a ssociate
a data field o r method w ith the class as a whole (rather than with the individual objects of the class). There is only
a single copy o f such an entity, and every obje ct that uses it is using the sa me (one a nd only) copy. In C++ we create
such entities by using the keyword static. (Note that this ke yword is used for about fo ur different purposes in
C++, so don’t get co nfused with oth er places wh ere you migh t come acr oss it.

Study
Study all of section 3.7 of J&K now.

5.4 Pointers, this

Pointers play an important role in C+ +. There is a special keywo rd, this, which can only be used inside a class,
and which sta nds for a po inter to the curre nt object.

Study
Study all of section 3.8 of J&K now.

5.5 Exercises

1 Write a class called point, which is capable of representing the coordinates of a point on a graph. Your
class must permit the creation of variables as follows:

point p, q(2.1, -4.3);

5.6
csc2402 — Object-Oriented Programming in C++ Study Guide

In the above example, p should be created with coord inates (0,0), w hilst q should have coordina tes (2.1,-
4.3). Your class should have methods as follows:

x() returns the x coordinate.


y() returns the y coordinate.
r() returns the distance from the origin.
theta() returns the ang le to the x axis.
set_x(val) sets the x coordinate to val.
set_y(val) sets the y coordinate to val.
Also provide a copy constructor.

The formula for calculating r from x and y is: r = square ro ot of (x 2 + y 2).

The formula for calculating theta is atan2(y, x). (See the atan2 man page .)

2 Do problem 3.2 (ISBN book numbers) on page 169 of J&K.

3 A time class is needed. An ob ject of this class needs functions to input and outpu t the time as days, hours,
minutes, and seconds. A set_time function is also needed to set the value of the time from a value supplied
as seconds in a long, and another set_ time function tha t sets the time from a string. Finally, a function to
add two times is needed (make it add the second time to the time stored in the first time value).

For example, we want to be able to write:

time t1, t2;


t1.set_time(23000L); // set to 23000 seconds
cout << "The first time is :";
t1.output(); cout << endl;
cout << "Now enter another time: ";
t2.input();
t1.add(t2);
cout << "\nThe sum of the times is :";
t1.output(); cout << endl;
Times should be input and output as "dd:hh:mm:ss".

4 Without using the STL, write a set class that implements a set of zero o r more integ ers in the range 0 to
127. You should provide the follow ing operations:

* Create an e mpty set,

* insert a value into the set,

* remove a n element fro m the set,

* compute the intersection of two se ts, that is a set of only those elements found in both sets,

* compu te the union o f two sets, that is, a set of tho se elements fo und in either se t,

* given an integer, return the next element in the set that is larger than the integer (or -1 if the re is
no such integer).

5 (Harder) Design a class for holding really huge floating point numbe rs. Use a class containing a double
to hold a value, and a long to hold an additional multiplier for the power. For example, if the double
is d and the multiplier is m, then the value of the number so rep resented is d×10 m. Write a fun ction to
normalise such a number, that is reduce it to a form where the power stored within d is 0. This is done by
repeated ly dividing d by 2 until it is less than 1 and, foe each division, adding 1 to m. Then rep eatedly
multiply d by 2 until it is greater than or equal to 0.5 and, for each multiplication, subtract 1 from m.
Multiplication is done by multiplying the two ds and adding the two ms. Addition is tric kier.

5.7
csc2402 — Object-Oriented Programming in C++ Study Guide

Summative Practical Exercises


Work problem 4 above.

5.8

Вам также может понравиться