Object-Oriented Programming in C

++

Module

0
Written by Ron House

Quick Overview

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 oldstyle 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 Programming

1
Written by Ron House

csc2402 — Object-Oriented Programming in C++ 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

Study Guide

[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++ Object-oriented programming: Impleme ntation is in a pro gramming language suc h as C++ .

Study Guide

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 N

Maths operators in ordinary programming languages (for example, `+' works on ints, floats, etc.) 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 ectoriented. 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++ }; struct rectangle { double length, height; };

Study Guide

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

2
Written by Ron House

C and C++

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: int fred(); int fred(a,b) float a; int b; { ... }

ANSI method: int fred(float, int); int fred(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). There are new re served keywords:

2.

and bool delete friend not private this typename xor_eq

and_eq catch dynamic_cast inline not_eq protected throw using

asm class explicit mutable operator public true virtual

bitand compl export namespace or reinterpret_cast try wchar_t

bitor const_cast false new or_eq template typeid xor

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; ip = vp; ip = (int*)vp; Initialising character arrays: // // // C++ Legal Legal Legal does not C and C++ C, illegal C++ C and C++ allow chopping the nul character off a string in an initialisation:

6.

7. 8. 9.

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 same as sizeof(char) in C++, but it is the same as sizeof(int) in C. enum works better in C++. (The scope of enum constants is pro perly scop ed, rather tha n global.) [See J&K page 41] 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. 2.

Classes (of course — heaps of features here, which we shall discuss a lot more later). 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++ int x = 10; twice(x); /* Here, x is 20 */

Study Guide

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(); setup(75); is the same as is the same as setup(100,50); 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

7. 8.

... c = a + b; new and delete operators: These are a safer version of the malloc and free functions in C. You should never use the C functions in C++. [See J&K pages 70-73] 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. 10.

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. 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] 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>

11.

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] File streams: The stream i-o system can, of course, be used on files. [See J&K section 2.3] 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] 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]

14. 15. 16.

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
1

Exercises
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 4 5 Is it legal to #include a standard C library header file in a C++ program? Why is it better to use an inline function than a #define statement? (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. A declaration (function heading) for a function called jill with no arguments, returning a pointer to a double. A declaration for a pointer variable called fred that could point to a function such as joe, described in (a) above. A statement that makes fred (see (c) above) point to joe (see (a) above). A declaration for a variable called arr that is a pointer capable of pointing to ten ints. A statement that makes arr actually point to ten ints. (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. 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.

b

c

d e f g

h

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++ a b c d e f g h 7 { int i = 7; printf("%d\n", i == 7); } { int i = 7; printf("%d\n", i == 2); } { int i = 3; printf("%d\n", i << 2); } { int a[2] = {3, 7}; printf("%d\n", *(a+1)); } { int a[2] = {3, 7}; printf("%d\n", a[1]); } { int a[2] = {3, 7}; printf("%d\n", *a+1); } { int a[2] = {3, 7}, *p = a; printf("%d\n", * ++p); } { int a[2] = {3, 7}, *p = a; printf("%d\n", ++ *p); }

Study Guide

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

3
Written by Ron House

Standard I-O in C++

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 2 The facilities ar e integrated, ra ther than a who le lot of separa te functions. The compiler `knows what's going on', so it can check the sanity of the various operations better than C can with <stdio.h>. You can derive your own specialised classes from the ones provided. (Only likely in very advanced program s.)

3

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++ cout << fvar << ivar;

Study Guide

[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& ostream& ostream& ostream& ostream& ostream& ... operator<<( signed operator<<(unsigned operator<<( signed operator<<(unsigned operator<<(float); operator<<(double); char); char); int); int);

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; cout << hex << ivar; cin >> hex >> ivar; cout << oct << ivar; cin >> oct >> ivar; cin >> ws; cout << endl; cout << ends; cout << flush;

hex (hex) E.g.

oct (octal) E.g.

ws (skip whitespace) E.g. endl (newline & flush) E.g. ends (output nul) E.g. flush (flush output) E.g.

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 ios_base::skipws ios_base::left ios_base::right ios_base::scientific ios_base::fixed ios_base::dec ios_base::oct ios_base::hex ios_base::uppercase ios_base::showbase ios_base::showpoint ios_base::showpos Purpose Skips whitespace left-justify right-justify Use scientific notation Use fixed notation Use decimal notation Use octal notation Use hexadecimal notation Use upper case letters in nos. Prefix 0x for hex & 0 for octal Always put d ecimal po int in floats Put + sign on positive nos.

3.6

csc2402 — Object-Oriented Programming in C++ As before, if your compiler won’t let you have ios_base , try plain old ios.

Study Guide

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 b c d e f g 2 { int i = 4; cout << (i == 8, 2) << " " << i << endl; } { int i = 4; cout << (i = 8, i == 4) << endl; } { int i = 4; cout << setw(4) << (i = 8, i == 4) << endl; } { int x[4]; cout << sizeof x/sizeof(int) << endl; } { int x[4]; cout << sizeof x/sizeof(int) << endl; } { const char *p = "Hello\n"; cout << sizeof p << endl; } { const char p[] = "Hello\n"; cout << sizeof p << endl; }

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

+-----|* | * | * | * | * | * 3 4 Program as many exercises from J&K chapter 2 as you have time for. 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. 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.

5

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 Data Types

4
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. compiletime) 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-landinggear' 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 { string name; int age; };

class Person { public: 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++ } return 0; }

Study Guide

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++ 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'; } }

Study Guide

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(); ...etc.

// Declaration for the constructor function

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; void **items;

// Maximum and current size // Pointer to array of void

pointers

public: /**** stack: Constructor ****** On entry: size is the maximum number of
in stack.

elements to be stored

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++ On exit:

Study Guide

stk),

If stack not empty, returns top item (not removed from 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++ return 1; } int stack :: stack_empty() { return (sp == 0); } void *stack :: stack_pop() { void *item; if (stack_empty()) { return NULL; } item = stack_top(); sp--; return item; } void *stack :: stack_top() { if (stack_empty()) { return NULL; } return items[sp-1]; } int stack :: stack_count() { return sp; } // succeed

Study Guide

// If true, stack is empty

// Check for item on stack

// Get top item. // Pop it from stack

// Check for item on stack

// Return data address

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); cout << "Enter names:\n"; while (can_load_name(s)) { // Try again } cout << "Names are:\n";

// Declare stack variable

// All names loaded; now unload while (! s.stack_empty()) { // unload_name(s); // } return 0; // }

and output. Still more? yes - pop and print Destructor called here for s.

4.12

csc2402 — Object-Oriented Programming in C++ // 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;

Study Guide

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 struct listnode *next; void *item; } listnode; #include <iostream> using namespace std; #include "stacklnk.h" stack :: stack(int) { list = NULL; itemcount = 0; return; } // Note missing parameter name 1 // No nodes // so count is 0
list

items

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

Study Guide

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 b c d A class constructor cannot be private. A class may have pub lic variables. A class may have private functions. 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. (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. (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.

6.

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

9.

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

Summative Practical Exercises Work problems 7 and 8 above.

4.18

Object-Oriented Programming in C++

Module

5
Written by Ron House

More on Classes

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++ Dynamic: * Month *m=new Month("Jan");

Study Guide

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
1

Exercises
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 3 Do problem 3.2 (ISBN book numbers) on page 169 of J&K. 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

Sign up to vote on this title
UsefulNot useful