1 Building Classes (the "++" in C++) (Chapter 14) Representing More Complex Objects.

Slides:



Advertisements
Similar presentations
Class and Objects.
Advertisements

True or false A variable of type char can hold the value 301. ( F )
Classes. COMP104 Lecture 25 / Slide 2 Motivation  Types such as int, double, and char are simple objects. * They can only answer one question: “What.
Classes. COMP104 Class / Slide 2 Motivation  Types such as int, double, and char are “stupid” objects. * They can only answer one question: “What value.
Starting Out with C++: Early Objects 5/e © 2006 Pearson Education. All Rights Reserved Starting Out with C++: Early Objects 5 th Edition Chapter 6 Functions.
Chapter 14: Overloading and Templates
This set of notes is adapted from that provided by “Computer Science – A Structured Programming Approach Using C++”, B.A. Forouzan & R.F. Gilberg, Thomson.
Classes and OOP. Basic, built-in, pre-defined types : char, int, double, … Variables + operations on them int a, b,c; c=a+b; c=a mod b; … More complicated,
1 Lab Session-XIV CSIT121 Spring 2002 b Namespaces b First Class Travel b Lab Exercise 14 (Demo) b Lab Exercise b Practice Problem.
Chapter 6. 2 Objectives You should be able to describe: Function and Parameter Declarations Returning a Single Value Pass by Reference Variable Scope.
Chapter Objectives You should be able to describe: Object-Based Programming Classes Constructors Examples Common Programming Errors.
Chapter 11: Classes and Data Abstraction
C++ Functions. 2 Agenda What is a function? What is a function? Types of C++ functions: Types of C++ functions: Standard functions Standard functions.
Chapter 6: Functions.
Classes Representing Non-Trivial Objects. Problem Write a program that reads a temperature (either Fahrenheit or Celsius), and displays that same temperature.
Modular Programming Chapter Value and Reference Parameters t Function declaration: void computesumave(float num1, float num2, float& sum, float&
1 Chapter 9 Scope, Lifetime, and More on Functions.
Chapter 9 Defining New Types. Objectives Explore the use of member functions when creating a struct. Introduce some of the concepts behind object-oriented.
© The McGraw-Hill Companies, 2006 Chapter 4 Implementing methods.
Modular Programming Chapter Value and Reference Parameters computeSumAve (x, y, sum, mean) ACTUALFORMAL xnum1(input) ynum2(input) sumsum(output)
Chapter 8 Friends and Overloaded Operators. Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2 Overview Friend Function (8.1) Overloading.
1 3. More About Data Structures and ADTs: C++ Data types (Read §3.1 & §3.2) C++ types an be classified as: Fundamental (or simple or scalar): A data object.
Copyright 2003 Scott/Jones Publishing Standard Version of Starting Out with C++, 4th Edition Chapter 6 Functions.
Copyright © 2012 Pearson Education, Inc. Chapter 6: Functions.
Chapter 5 Functions For All Subtasks. Void functions Do not return a value. Keyword void is used as the return type in the function prototype to show.
Matrices Introducing Inheritance. Consider A matrix is a grid in which numbers can be stored. Algorithms for problems in scientific computing frequently.
Chapter 11: Classes and Data Abstraction. C++ Programming: Program Design Including Data Structures, Fourth Edition2 Objectives In this chapter, you will:
Operatorsand Operators Overloading. Introduction C++ allows operators to be overloaded specifically for a user-defined class. Operator overloading offers.
Defining New Types Lecture 21 Hartmut Kaiser
Operator Overloading Version 1.0. Objectives At the end of this lesson, students should be able to: Write programs that correctly overload operators Describe.
Chapter 13. Procedural programming vs OOP  Procedural programming focuses on accomplishing tasks (“verbs” are important).  Object-oriented programming.
Learners Support Publications Classes and Objects.
Copyright 2004 Scott/Jones Publishing Alternate Version of STARTING OUT WITH C++ 4 th Edition Chapter 7 Structured Data and Classes.
ADTs and C++ Classes Classes and Members Constructors The header file and the implementation file Classes and Parameters Operator Overloading.
Concordia University Department of Computer Science and Software Engineering Click to edit Master title style ADVANCED PROGRAM DESIGN WITH C++ Part 9:
CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element.
Classes Representing Non-Trivial Objects. Problem Write a program that reads a temperature (either Fahrenheit or Celsius), and displays that same temperature.
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved More about.
Class Miscellanea Details About Classes. Review We’ve seen that a class has two sections: class Temperature { public: //... public members private: //...
Functions Overview Functions are sequence of statements with its own local variables supports modularity, reduces code duplication Data transfer between.
Practice Building Classes Modeling Objects. Problem Write a program that computes the Dean’s List (full-time students whose GPA 3.0), using a student.
Alternate Version of STARTING OUT WITH C++ 4 th Edition Chapter 6 Functions.
Copyright © 2002 W. A. Tucker1 Chapter 10 Lecture Notes Bill Tucker Austin Community College COSC 1315.
Chapter 10: Classes and Data Abstraction. Objectives In this chapter, you will: Learn about classes Learn about private, protected, and public members.
Chapter 11 Friends and Overloaded Operators. Introduction to function equal // Date.h #ifndef _DATE_H_ #define _DATE_H_ class CDate { public: CDate();
1 More Operator Overloading Chapter Objectives You will be able to: Define and use an overloaded operator to output objects of your own classes.
By Joaquin Vila Prepared by Sally Scott ACS 168 Problem Solving Using the Computer Week 13 More on Classes Chapter 8 Week 13 More on Classes Chapter 8.
C++ Programming: From Problem Analysis to Program Design, Third Edition Chapter 15: Overloading and Templates.
Chapter 6 Functions. Topics Basics Basics Simplest functions Simplest functions Functions receiving data from a caller Functions receiving data from a.
C++ Programming: From Problem Analysis to Program Design, Fifth Edition Chapter 05: Classes and Data Abstraction.
 2003 Prentice Hall, Inc. All rights reserved. 1 Chapter 3 - Functions Outline 3.15Functions with Empty Parameter Lists 3.16Inline Functions 3.17References.
Chapter 10: Classes and Data Abstraction. Classes Object-oriented design (OOD): a problem solving methodology Objects: components of a solution Class:
Manipulator example #include int main (void) { double x = ; streamsize prec = cout.precision(); cout
Reference Parameters There are two ways to pass arguments to functions: pass- by-value and pass-by-reference. pass-by-value –A copy of the arguments’svalue.
Chapter 6 Functions. 6-2 Topics 6.1 Modular Programming 6.2 Defining and Calling Functions 6.3 Function Prototypes 6.4 Sending Data into a Function 6.5.
Friend Functions. Problem u Assuming two Complex objects u How would one add two numbers? W + X Complex operator+(const Complex& w, const Complex& x);
Structure A Data structure is a collection of variable which can be same or different types. You can refer to a structure as a single variable, and to.
CPSC 252 ADTs and C++ Classes Page 1 Abstract data types (ADTs) An abstract data type is a user-defined data type that has: private data hidden inside.
100 學年度碩士班新生暑期課程 程式設計 Object-Oriented Programming: Part I The Basics of Classes.
FUNCTIONS (C) KHAERONI, M.SI. OBJECTIVE After this topic, students will be able to understand basic concept of user defined function in C++ to declare.
Defining Data Types in C++ Part 2: classes. Quick review of OOP Object: combination of: –data structures (describe object attributes) –functions (describe.
Class Operations Creating New Types. Review Last time, we began building, a class to allow us to model temperatures: Last time, we began building Temperature,
Function Parameters and Overloading Version 1.0. Topics Call-by-value Call-by-reference Call-by-address Constant parameters Function overloading Default.
Visit for more Learning Resources
Introducing Inheritance
The dirty secrets of objects
Classes and OOP.
COP 3330 Object-oriented Programming in C++
Standard Version of Starting Out with C++, 4th Edition
Lecture 2 – Abstract Data Type (ADT)
Presentation transcript:

1 Building Classes (the "++" in C++) (Chapter 14) Representing More Complex Objects

Problem 2 Develop a type to model temperatures with various operations such as Fahrenheit/Celsius conversion, input, and output. However, a temperature object has two attributes its degrees (a double), and its scale (a character) and we can't represent it by a single type provided in C++. When this happens, we can create our own type by building a class to model the object (temperature) being represented. Other Examples: (Final Lab & Proj.) Coordinate objects: x-coordinate y-coordinate Fraction objects: numerator denominator Time objects: hours minutes seconds AM/PM

class Temperature { double myDegrees; char myScale; }; Such variables are called the class' data members (also referred to as instance variables or attribute variables). 3 Note the semicolon Function prototypes for built-in operations go here private: For a declaration C obj; where C is a class, the object obj is also called an "instance of C." When learning how to build classes, it helps to pretend that we are the temperature object ; beginning each attribute name with " my " helps reinforce this internal perspective. We begin by declaring variables to store the attributes of the object being represented (a temperature), and wrap these inside a class declaration in Temperature.h : Building a Class public:

Information Hiding Classes have a public section and a private section. (In fact, it may have more than one of each.) The public section provides the interface to users of the class; items declared in it are accessible to them. The private section contains implementation details. Items declared in it are inaccessible to users of the class and are said to be "hidden." Data members should go in the private section to prevent programmers from writing programs that access data members directly. 4 "What" a class provides "How" a class provides it Why? So users can't put invalid data in them. Also to allow changes to them in class revisions. e.g., in a Temperature object: set myScale = 'X' In a Fraction object: set myDenominator = 0

A New Type We have now created a new type Temperature, so we can use it in a program: #include "Temperature.h" // class Temperature... Temperature aTemp; The object aTemp can be visualized as follows: The data members myDegrees and myScale within aTemp are uninitialized. We need a way to put values in them. 5 myDegrees myScale aTemp ? ?

Operations and Messages As of now, our Temperature objects are just data containers (like structs in C) — they have no built-in ("push-button") operations by which users can process them. Instead they have to be "shipped off" to various functions for processing. So, our next task in building a class is to: Decide what operations to provide How to implement them 6 This may involve adding new data members

Operations on a class object are usually implemented as class function members (also called methods). To call a function member, we use the dot operator: object.method() 7 This can be thought of as the caller sending object a message named method. The definition of a function member details how object responds to the message. The "pushbutton" operator

Function Member Example: Output As we have noted, we have no way to put values in the data members of a Temperature object. Normally, function members (called constructors) that make this possible would be the first ones that we add to a class. However, we will instead look at an output operation because it is easier to understand. 8 Lab: Help with debugging other ops.

Suppose we want to display the value of a Temperature object aTemp by sending it a display() message: aTemp.display(cout); or aTemp.display(cerr); Using the internal perspective (where I am the Temperature object receiving the message), we have the following specification for the function member display() : Receive: An ostream object that we'll call out Output: myDegrees and myScale, via out. Pass back: out, containing the new values. 9

Function Member Prototypes class Temperature { public: void display(ostream & out) const; private: double myDegrees; char myScale; }; This informs the compiler that class Temperature has a function member named display(), and that Temperature objects should "understand" the display() message. It also makes this display() operation accessible to users of our class. 10 We declare prototypes of function members in the public section of a class:

Function Member Definitions void Temperature::display(ostream & out) const { out << myDegrees << ' ' << myScale; } The function returns nothing, so its return-type is void. The full name Temperature::display() tells the compiler this is a function member of class Temperature. This function receives an ostream that it needs to change (by outputting something into it) and pass back, so we need a reference parameter for it. Function members that are not allowed to change any data members should be declared as const function members. Definition of display() : 11

class Temperature {... }; // end of class declaration inline void Temperature::display(ostream & out) const { out << myDegrees << ' ' << myScale; } Definitions of function members usually go in the implementation (.cpp) file. But when they are simple (say, with 6 or fewer operations), they are, for efficiency, usually put in the header file, below the class declaration, and specified as inline — especially if they are called often. 12 Inlining a function allows the compiler to replace calls to it with the actual code of the definition, thus eliminating the overhead of a function call. Simple ordinary functions can also be inlined to improve a program's efficiency — see §10.4

Problem At present, a Temperature declaration Temperature aTemp; leaves aTemp 's data members uninitialized. So if we output it, aTemp.display(cout); we cannot expect any meaningful results — rather, "garbage." 13 It would be better if we could be assured that Temperature objects were auto-initialized to some meaningful default value (e.g., 0 C ). To accomplish this, we can use a special function member called a default constructor.

Constructors A class constructor is a function member whose task is to initialize the class' data members. Because all they do is initialize data members, they don't return anything, and so their specification is often given as a postcondition — a boolean expression that indicates the state of the object after the constructor terminates. Default Constructor Specification: Postcondition: myDegrees == 0 && myScale == 'C'. 14

Default Constructor Prototype class Temperature { public: Temperature(); void display(ostream & out) const; private: double myDegrees; char myScale; }; The name of a constructor is always the name of the class (in this case Temperature() ). Since it returns nothing, a constructor has no return type (not even void ). Since they specify the first thing a user of the class needs to know (i.e., how to define class objects), constructor prototypes are usually the first function members listed in the public section of the class. 15

Default Constructor Definition As a function member of class Temperature, its full name is Temperature::Temperature(). And because it is so simple and gets called often, we inline the definition and put it below the class declaration in Temperature.h. // In Temperature.h, after class declaration inline Temperature::Temperature() { myDegrees = 0; myScale = 'C'; } 16

Object Declarations A programmer can now make declarations like Temperature aTemp; and object can be visualized as follows: and object aTemp can be visualized as follows: Each declaration of a class object will generate an automatic call to a class constructor. 17 myDegrees myScale aTemp 0.0 C

Testing //... documentation //... other #includes #include "Temperature.h" int main() { Temperature aTemp; aTemp.display(cout); } 18 To test this, we can write: To test this much, we can write: Lab: fractionTester.cpp Execution : 0 C

Problem 2 At present, we can only initialize a Temperature object to a default value: Temperature aTemp;, w. The mechanism that makes it possible to initialize an object to other values is function overloading, which allows two different functions to have the same name. The same name can be used to define different functions, provided each function has a different signature (the list of the parameter types). The compiler will determine which function to use from the number and type of arguments in a function call. 19

Another Constructor So, to overload the constructor, we just provide a second constructor that differs from all other constructors in at least one parameter type. 20 But this is easy; we simply have the second constructor — called an explicit-value constructor — receive the initial values we want a Temperature object to have via its parameters and use these parameter values to initialize the class' data member. Explicit-Value Constructor Specification: Receive: degrees, a double; scale, a char. Precondition: scale == 'F' || scale == 'C'. Postcondition: myDegrees == degrees && myScale == scale. State of the object

Explicit-Value Constructor Prototype class Temperature { public: Temperature(); Temperature(double degrees, char scale); void display(ostream & out) const; private: double myDegrees; char myScale; }; 21

As before, because of its simplicity and constructors get called often, we put this (second) constructor definition in Temperature.h below the class declaration and inline it. // In Temperature.h, after class declaration inline Temperature::Temperature(double degrees, char scale) { assert(scale == 'F' || scale == 'C'); myDegrees = degrees; myScale = scale; } 22 Explicit-Value Constructor Definition

Object Definitions A programmer can now write: Temperature temp1, and temp1 and temp2 are defined as follows: The compiler uses the number of arguments in a declaration to decide which constructor to use in initializing an object. myDegrees myScale temp1 C 0.0 myDegrees myScale temp2 F Default constructor Explicit-value constructor temp2(98.6, 'F');

Testing To test this much, we can write: //... documentation //... other #includes #include "Temperature.h" int main() { Temperature temp1, temp2(98.6, 'F'); temp1.display(cout); cout << endl; temp2.display(cout); } 24 Execution : 0 C 98.6 F

25 /*---- Temperature.h Header file for Temperature class. Operations: Constructors: default display(): output a Temperature object */ #include class Temperature { public: Temperature(); Temperature(double degrees, char scale); void display(ostream & out) const; private: double myDegrees; char myScale; }; //-- Definition of default constructor inline Temperature::Temperature() { myDegrees = 0; myScale = 'C'; } Our Temperature Class... so far and explicit-value

26 //-- Definition of display() inline void Temperature::display(ostream & out) const { out << myDegrees << ' ' << myScale; } /*---- Temperature.cpp Implementation file for Temperature class */ //-- STILL EMPTY //-- Definition of explicit-value constructor inline Temperature::Temperature(double degrees, char scale) { assert(scale == 'F' || scale == 'C'); myDegrees = degrees; myScale = scale; }

27 /* Explicit-value constructor Receive: degrees, a double; scale, a char. Precondition: scale == 'F' || scale == 'C'. Postcondition: myDegrees == degrees && myScale == scale */ Temperature(double degrees, char scale); /*---- Temperature.txt Documentation file for Temperature class. Operations: Constructors: default and explicit-value display(): output a Temperature object read(): input a Temperature object */ class Temperature { public: /* Default constructor Postcondition: myDegrees == 0 && myScale == 'C' */ Temperature();

28 /* Output function member Receive: out, an ostream. Output: myDegrees and myScale, via out. Passback: out, containing the new values */ void display(ostream & out) const; private: double myDegrees; char myScale; }; /*---- tempTester.cpp Driver program to test Temperature class */ #include using namespace std; #include "Temperature.h" int main() { Temperature temp1; temp1.display(cout); // displays 0 C cout << endl; temp2.display(cout); // displays 98.6 F cout << endl; } Execution : 0 C 98.6 F, temp2(98.6, 'F');

Accessor Functions The values in the data members of a Temperature object are not accessible to a user of our class. To make them available, we provide function members, called accessor functions, that retrieve these values: 29 class Temperature { public: Temperature(); Temperature(double degrees, char scale); double getDegrees() const; char getScale() const; private: double myDegrees; char myScale; }; const because they only access data members, don't modify them.

inline double Temperature::getDegrees() const { return myDegrees; } inline char Temperature::getScale() const { return myScale; } Because they are simple one-line functions, they can be defined in the header file as inline functions. 30 Temperature temp1; //... cout << "Its degrees is " << temp1.getDegrees() << " and its scale is " << temp1.getScale() << endl; Use in a program:

Input It is also useful to be able to input a value for a Temperature object. From the internal perspective, we can specify this task as follows. 31 Specification: Receive: in, an istream. Precondition: in contains valid degrees and scale values. Input: the degrees and scale values from in. Passback: in, minus its degrees and scale values. Postcondition: myDegrees == degrees && myScale == scale.

Input: Prototype Note that unlike output, the input operation changes the class data members, and so is not a const function. 32 class Temperature { public: Temperature(); Temperature(double degrees, char scale); void read(istream & in); void display(ostream & out) const; double getDegrees() const; char getScale() const; private: double myDegrees; char myScale; };

Input: Definition void Temperature::read(istream & in) { double degrees; char scale; in >> degrees >> scale; scale = toupper(scale); // Change 'f', 'c' // Check precondition assert(scale == 'C' || scale == 'F'); myDegrees = degrees; // Valid input, so myScale = scale; // set data members } Input is an easy place for errors to occur, so always carefully check the preconditions of an input function. We put this in Temperature.cpp rather than inline it like we did display() since it's more complicated. 33 Temporary holding area for input so we can validate it before putting it in the data members

Testing //... documentation //... other #includes #include "Temperature.h" int main() { cout << "\nEnter a temperature: "; Temperature temp3; temp3.read(cin); // read it temp3.display(cout); // echo it back cout << endl; } 34 Execution : Enter a temperature: 32F 32 F

Conversion Functions To find the Celsius or Fahrenheit equivalent of a Temperature object, we want to be able to send it a toCelsius() or toFahrenheit() message: Temperature temp1, temp2; //... temp2 = temp1.toCelsius(); //... temp1 = temp2.toFahrenheit(); From the internal perspective, our specifications are: toCelsius(): Return the Celsius equivalent of myself. toFahrenheit(): Return the Fahrenheitequivalent of myself. 35

Conversion-function Prototypes These operations won't alter the class data members, and so are declared as const function members. class Temperature { public: Temperature(); Temperature(double degrees, char scale); void read(istream & in); void display(ostream & out) const; double getDegrees() const; char getScale() const; Temperature toCelsius() const; Temperature toFahrenheit() const; private: double myDegrees; char myScale; }; 36

Conversion-function Definitions Temperature Temperature::toCelsius() const { switch (myScale) { case 'C': return Temperature(myDegrees, 'C'); case 'F': return Temperature((myDegrees - 32)/1.8, 'C'); default: cerr << "\nInvalid scale: " << myScale << " in Celsius().\n" << endl; exit(1); } 37 In Temperature.cpp Temperature Temperature::toFahrenheit() const { switch (myScale) { case 'F': return Temperature(myDegrees, 'F'); case 'C': return Temperature(1.8 * myDegrees + 32), 'F'); default: cerr << "\nInvalid scale: " << myScale << " in Celsius().\n" << endl; exit(1); } Note how our explicit-value constructor is used to build the return values.

Testing #include "Temperature.h" int main() { cout << "\nEnter a temperature: "; Temperature temp1, temp2; temp1.read(cin); temp2 = temp1.toCelsius(); temp2.display(cout); // or we can chain the messages together: // temp1.toCelsius().display(cout); cout << endl; temp1 = temp2.toFahrenheit(); temp1.display(cout); cout << endl; } 38 We test the correctness of this function in the tester program on slides

An Arithmetic Operator:  (subtraction) Nearly any C++ operator  can be overloaded for a new type by defining a function named operator  () for that type. For example, if a and b are int s, we could write the expression a + b as the function call operator+(a, b). If a and b are objects of type C (where C is a class), two different versions of this function are possible; for example, a.operator+(b), if operator+() is a function member of C operator+(a, b), an ordinary function otherwise 39 For our Temperature class, either method could be used to define a subtraction operation, but we will use the first. So we have the following internal specification for our function operator-() : Receives: a Temperature object temp2 Returns: The difference between myself and temp2

Prototype Since this operation won't alter the class data members, it is declared as a const function member. 40 class Temperature { public: Temperature(); Temperature(double degrees, char scale); void read(istream & in); void display(ostream & out) const; double getDegrees() const; char getScale() const; Temperature toCelsius() const; Temperature toFahrenheit() const; Temperature operator-(const Temperature & temp2) const; private: double myDegrees; char myScale; };

Definition Temperature Temperature::operator- (const Temperature & temp2) const { Temperature result; if (myScale == 'F') { result.myDegrees = myDegrees - temp2.toFahrenheit().getDegrees(); result.myScale = 'F'; } else { result.myDegrees = myDegrees - temp2.toCelsius().getDegrees(); result.myScale = 'C'; } return result; } 41 In Temperature.cpp We test the correctness of this function in the tester program on slides

The Output Operator << Instead of writing: temp1.display(cout); cout << endl; that is, overload << for our Temperature class. We can do this by defining the function operator<<() for it. However, because the left operand ( cout ) is an ostream object and not a Temperature object (and we are unable to modify the ostream class), we cannot implement this operation as a function member of the Temperature class. So we define it as an ordinary function with two parameters, an ostream and a Temperature ; i.e., cout << temp1 is the same as operator<<(cout, temp1) it would be more convenient if we could write: cout << temp1 << endl; 42

Definition // In Temperature.h, after the class declaration inline ostream & operator<<(ostream & out, const Temperature & temp) { temp.display(out); return out; } 43 Notes about this definition: operator<<() is not a function member, so:  It is not prototyped inside the class declaration  It's name is not qualified by Temperature:: Because of it's simplicity, we inline this definition and put it below the class declaration in Temperature.h. Note: No Temperature::

44 The function must modify the actual ostream it receives via out (because output is inserted into it ), so out must be a reference parameter. Chaining << operations together as in cout << temp1 << endl; is executed as a composition of function calls: operator<<( operator<<(cout,temp1), endl); This means that the first function call must return the ostream out to which it is sending output so the second function call can use it. However, the normal function-return mechanism makes a copy of what is returned and we need to return out, not a copy of out. This copying mechanism can be turned off by making the function's return type a reference ( ostream & ).

The Input Operator >> Similar to output, it would be more convenient if instead of temp1.read(cin); temp2.read(cin); And we can do this in a manner similar to that for output by defining an ordinary function named operator>> that uses our read() function member. to input two Temperature objects, we could write: cin >> temp1 >> temp2; 45 // In Temperature.h, after the class declaration inline istream & operator>>(istream & in, Temperature & temp) { temp.read(in); return in; } One difference: temp isn't a constant reference parameter since it must be changed.

46 /*---- Temperature.h Header file for Temperature class. Operations: Constructors: default and explicit-value display(): output a Temperature object read(): input a Temperature object getDegrees(), getScale(): accessors toCelsuis(): Fahrenheit to Celsius converter toFahrenheit(): Celsuis to Fahrenheit converter > : output and input operators */ #include class Temperature { public: Temperature(); Temperature(double degrees, char scale); void display(ostream & out) const; void read(istream & in); double getDegrees() const; char getScale() const; Temperature toCelsius() const; Temperature toFahrenheit() const; Temperature operator-(const Temperature & temp2) const; private: double myDegrees; char myScale; }; Our Complete Temperature Class

47 //-- Definition of default constructor inline Temperature::Temperature() { myDegrees = 0; myScale = 'C'; } //-- Definition of explicit-value constructor inline Temperature::Temperature(double degrees, char scale) { assert(scale == 'F' || scale == 'C'); myDegrees = degrees; myScale = scale; } //-- Definition of display() inline void Temperature::display(ostream & out) const { out << myDegrees << ' ' << myScale; } //-- Definition of getDegrees() inline double Temperature::getDegrees() const { return myDegrees; } //-- Definition of getScale() inline char Temperature::getScale() const { return myScale; }

48 /*---- Temperature.cpp Implementation file fzor Temperature class */ #include using namespace std; #include "Temperature.h" //-- Defininition of << inline ostream & operator<<(ostream & out, const Temperature & temp) { temp.display(out); return out; } //-- Defininition of >> inline istream & operator>>(istream & in, Temperature & temp) { temp.read(in); return in; }

49 //-- Definition of read() void Temperature::read(istream & in) { double degrees; char scale; in >> degrees >> scale; scale = toupper(scale); // Check for 'f', 'c' // Check precondition assert(scale == 'C' || scale == 'F'); myDegrees = degrees; // Valid input, so myScale = scale; // set data members } //-- Definition of toCelsius() Temperature Temperature::toCelsius() const { switch (myScale) { case 'C': return Temperature(myDegrees, 'C'); case 'F': return Temperature((myDegrees - 32)/1.8, 'C'); default: cerr << "\nInvalid scale: " << myScale << " in Celsius().\n" << endl; exit(1); }

50 //-- Definition of toFahrenheit() Temperature Temperature::toFahrenheit() const { switch (myScale) { case 'F': return Temperature(myDegrees, 'F'); case 'C': return Temperature(myDegrees * , 'F'); default: cerr << "\nInvalid scale: " << myScale << " in toFahrenheit().\n" << endl; exit(1); } //-- Definition of operator-() Temperature Temperature::operator-(const Temperature & temp2) const { Temperature result; if (myScale == 'F') { result.myDegrees = myDegrees - temp2.toFahrenheit().getDegrees(); result.myScale = 'F'; } else { result.myDegrees = myDegrees - temp2.toCelsius().getDegrees(); result.myScale = 'C'; } return result; }

51 /*---- Temperature.txt Documentation file for Temperature class. Operations: Constructors: default and explicit-value display(): output a Temperature object read(): input a Temperature object getDegrees(), getScale: accessors toCelsuis(): Fahrenheit to Celsius converter toFahrenheit(): Celsuis to Fahrenheit converter > : output and input operators */ class Temperature { public: /* Default constructor Postcondition: myDegrees == 0 && myScale == 'C' */ Temperature(); /* Explicit-value constructor Receive: degrees, a double; scale, a char. Precondition: scale == 'F' || scale == 'C'. Postcondition: myDegrees == degrees && myScale == scale */ Temperature(double degrees, char scale);

52 /* Output function member Receive: out, an ostream. Output: myDegrees and myScale, via out. Passback: out, containing the new values */ void display(ostream & out) const; /* Input function member Receive: in, an istream. Input: degrees and scale, via in Precondition: scale == 'F' || scale == 'C' (lower case allowed) Passback: in, with the values removed */ void read(istream & in); /* Degrees accessor Returns: Value of myDegrees */ double getDegrees() const; /* Scale accessor Returns: Value of myScale */ char getScale() const;

53 /* Fahrenheit to Celsius converter Returns: Celsius equivalent of this Temperature object */ Temperature toCelsius() const; /* Celsius to Fahrenheit converter Returns: Fahrenheit equivalent of this Temperature object */ Temperature toFahrenheit() const; /* Subtraction Operator Recieves: Temperature object temp2 Returns: (This Temperature object) - temp */ Temperature operator-(const Temperature & temp2) const; private: double myDegrees; char myScale; };

54 /* Output operator << Receive: out, an ostream and Temperature object aTemp. Output: myDegrees and myScale values in aTemp, via out. Passback: out, containing the new values. Return: reference to out */ ostream & operator<<(ostream & out, const Temperature & aTemp); /* Input function member Receive: in, an istream. Input: degrees and scale, via in Precondition: scale == 'F' || scale == 'C' (lower case allowed) Postcondition: aTemp's data members are set to degrees and scale, respectively. Passback: in, with the values removed, and aTemp */ istream & operator>>(istream & in, Temperature & temp);

55 /*---- tempTester.cpp Driver program to test Temperature class */ #include using namespace std; #include "Temperature.h" int main() { Temperature temp1, temp2(98.6, 'F'), temp3, temp4; temp1.display(cout); // displays 0C cout << endl; temp2.display(cout); // displays 98.6F cout << endl; cout << "\nEnter a temperature: "; temp3.read(cin); // read a Temperature temp3.display(cout); // echo it back cout << endl; cout << "Its degrees is " << temp3.getDegrees() << " and its scale is " << temp3.getScale() << endl; temp4 = temp3.toCelsius(); cout << "Its Celsius equivalent is: "; temp4.display(cout); cout << "\nand the Fahrenheit equivalent of this is: "; temp4.toFahrenheit().display(cout); cout << endl;

56 temp4 = temp1 - temp3; cout << "(First original temperature) - (this temperature) is "; temp4.display(cout); temp4 = temp2 - temp3; cout << "\n(Second original temperature) - (this temperature) is "; temp4.display(cout); cout << endl; cout > and <<\n" << "Enter two temperatures: "; cin >> temp1 >> temp2; cout << "First temperature is " << temp1 << " and the second is " << temp2 << endl; } Execution : 0 C 98.6 F Enter a temperature: 88.1 F 88.1 F Its degrees is 88.1 and its scale is F Its Celsius equivalent is: C and the Fahrenheit equivalent of this is: 88.1 F (First original temperature) - (this temperature) is C (Second original temperature) - (this temperature) is 10.5 F Now, let's try I/O with >> and << Enter two temperatures: 111.1F 44.4C First temperature is F and the second is 44.4 C Note that these statements test not only I/O of a Temperature object, but also that chaining of the > operators works:

57 class Coordinate { public: Coordinate(); Coordinate(double x, double y); double getX() const; double getY() const; void read(istream & in); void display(ostream & out) const; Coordinate operator+(const Coordinate & point2) const; private: double myX, myY; }; Coordinate Coordinate::operator+(const Coordinate & point2) const { Coordinate result( ); return result; } myX + point2.getX(), myY + point2.getY()

58