Building Classes Representing More Complex Objects the " " in

advertisement
Building Classes
(the "++" in C++)
(Chapter 14)
Representing More Complex Objects
1
Problem
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
2
Building a Class
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:
class Temperature
{
public:
Function prototypes for
built-in operations go here
private:
double myDegrees;
char myScale;
};
Note the
semicolon
Such variables are called the class' data
members (also referred to as instance
variables or attribute variables).
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.
For a declaration
C obj;
where C is a class, the
object obj is also called
an "instance of C."
3
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.
Why?
So users can't put invalid data in them.
Also to allow changes to them in class
revisions.
"What" a
class
provides
"How" a
class
provides it
e.g., in a Temperature
object: set
myScale = 'X'
In a Fraction object:
set
myDenominator = 0
4
A New Type
We have now created a new type Temperature,
so we can use it in a program:
#include "Temperature.h"
...
Temperature aTemp;
// class Temperature
The object aTemp can be visualized as follows:
aTemp
myDegrees
myScale
?
?
The data members myDegrees and myScale
within aTemp are uninitialized. We need a way to
put values in them.
5
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
This may involve
adding new data
members
6
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()
The
"pushbutton"
operator
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.
7
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.
Lab:
Help with
debugging
other ops.
8
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
We declare prototypes of function members in the
public section of a class:
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
10
users of our class.
Function Member Definitions
Definition of display():
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.
11
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.
class Temperature
{
...
}; // end of class declaration
inline void Temperature::display(ostream & out) const
{
out << myDegrees << ' ' << myScale;
}
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
12
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."
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.
13
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
// In Temperature.h, after class declaration
inline Temperature::Temperature()
{
myDegrees = 0;
myScale = 'C';
}
• 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.
16
Object Declarations
A programmer can now make declarations like
Temperature aTemp;
and object aTemp can be visualized as follows:
aTemp
myDegrees
myScale
0.0
C
Each declaration of a class object will generate
an automatic call to a class constructor.
17
Testing
To test this much, we can write:
// ... documentation
// ... other #includes
#include "Temperature.h"
int main()
{
Temperature aTemp;
aTemp.display(cout);
}
Execution :
0 C
Lab:
fractionTester.cpp
18
Problem 2
At present, we can only initialize a Temperature object
to a default value:
Temperature aTemp;
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.
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
20
Explicit-Value Constructor Prototype
class Temperature
{
public:
Temperature();
Temperature(double degrees, char scale);
void display(ostream & out) const;
private:
double myDegrees;
char myScale;
};
21
Explicit-Value Constructor Definition
// In Temperature.h, after class declaration
inline Temperature::Temperature(double degrees,
char scale)
{
assert(scale == 'F' || scale == 'C');
myDegrees = degrees;
myScale = scale;
}
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.
22
Object Definitions
A programmer can now write:
Temperature temp1, temp2(98.6, 'F');
and temp1 and temp2 are defined as follows:
Default
constructor
temp1
Explicit-value constructor
myDegrees
myScale
0.0
C
temp2
myDegrees
myScale
98.6
F
The compiler uses the number of arguments in a
declaration to decide which constructor to use in
initializing an object.
23
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);
}
Execution :
0 C
98.6 F
24
Our Temperature Class ... so far
/*---- Temperature.h ----------------------------------------------Header file for Temperature class.
Operations:
Constructors: default and explicit-value
display(): output a Temperature object
------------------------------------------------------------------*/
#include <iostream>
#include <cassert>
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';
}
25
//-- 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;
}
/*---- Temperature.cpp --------------------------------------------Implementation file for Temperature class.
------------------------------------------------------------------*/
//-- STILL EMPTY
26
/*---- 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();
/*--------------------------------------------------------------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);
27
/*--------------------------------------------------------------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 <iostream>
using namespace std;
#include "Temperature.h"
int main()
{
Temperature temp1;, temp2(98.6, 'F');
}
temp1.display(cout);
cout << endl;
temp2.display(cout);
cout << endl;
// displays 0 C
Execution :
0 C
98.6 F
// displays 98.6 F
28
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:
class Temperature
{
public:
Temperature();
Temperature(double degrees, char scale);
double getDegrees() const;
char getScale() const;
const because
they only access
private:
data members,
double myDegrees;
don't modify them.
char myScale;
};
29
Because they are simple one-line functions, they can
be defined in the header file as inline functions.
inline double Temperature::getDegrees() const
{
return myDegrees;
}
inline char Temperature::getScale() const
{
return myScale;
}
Use in a program:
Temperature temp1;
// ...
cout << "Its degrees is "
<< temp1.getDegrees()
<< " and its scale is "
<< temp1.getScale() << endl;
30
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.
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.
31
Input: Prototype
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;
};
Note that unlike output, the input operation changes
the class data members, and so is not a const
function.
32
Input: Definition
void Temperature::read(istream & in)
{
double degrees;
char scale;
in >> degrees >> scale;
Temporary holding area for
input so we can validate it
before putting it in the data
members
scale = toupper(scale);
// Change 'f', 'c'
// Check precondition
assert(scale == 'C' || scale == 'F');
}
myDegrees = degrees;
myScale = scale;
// Valid input, so
//
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
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;
}
Execution :
Enter a temperature: 32F
32 F
34
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
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;
};
These operations won't alter the class data members,
and so are declared as const function members.
36
Conversion-function Definitions
Temperature Temperature::toCelsius() const
In
{
Temperature.cpp
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);
Note how our
}
explicit-value
}
constructor is
used to build the
return values.
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);
}
}
37
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;
}
We test the correctness of this function
in the tester program on slides 55-56.
38
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 ints, 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
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
39
Prototype
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;
};
Since this operation won't alter the class data
members, it is declared as a const function member.
40
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;
}
In
Temperature.cpp
We test the correctness of this function
in the tester program on slides 55-56.
41
The Output Operator <<
Instead of writing:
temp1.display(cout);
cout << endl;
it would be more convenient if we could write:
cout << temp1 << 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)
42
Definition
// In Temperature.h, after the class declaration
inline ostream & operator<<(ostream & out,
const Temperature & temp)
{
temp.display(out);
Note: No
Temperature::
return out;
}
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.
43
• 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 &).
44
The Input Operator >>
Similar to output, it would be more convenient if instead of
temp1.read(cin);
temp2.read(cin);
to input two Temperature objects, we could write:
cin >> temp1 >> temp2;
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.
// 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.
45
Our Complete Temperature Class
/*---- 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 <iostream>
#include <cassert>
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;
};
46
//-- 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;
}
47
//-- 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;
}
/*---- Temperature.cpp --------------------------------------------Implementation file fzor Temperature class.
------------------------------------------------------------------*/
#include <iostream>
using namespace std;
#include "Temperature.h"
48
//-- 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;
myScale = scale;
// Valid input, so
//
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);
}
}
49
//-- Definition of toFahrenheit()
Temperature Temperature::toFahrenheit() const
{
switch (myScale)
{
case 'F':
return Temperature(myDegrees, 'F');
case 'C':
return Temperature(myDegrees * 1.8 + 32, '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;
50
/*---- 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);
51
/*--------------------------------------------------------------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;
52
/*--------------------------------------------------------------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) - temp2
----------------------------------------------------------------*/
Temperature operator-(const Temperature & temp2) const;
private:
double myDegrees;
char myScale;
};
53
/*--------------------------------------------------------------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);
54
/*---- tempTester.cpp -----------------------------------------Driver program to test Temperature class
---------------------------------------------------------------*/
#include <iostream>
using namespace std;
#include "Temperature.h"
int main()
{
Temperature temp1, temp2(98.6, 'F'), temp3, temp4;
temp1.display(cout);
cout << endl;
temp2.display(cout);
cout << endl;
// displays 0C
// displays 98.6F
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;
55
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 << "\nNow, let's try I/O with >> 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
Note that these
statements test
not only I/O of a
Temperature
object, but also
that chaining of
the << and >>
operators works:
Enter a temperature: 88.1 F
88.1 F
Its degrees is 88.1 and its scale is F
Its Celsius equivalent is: 31.1167 C
and the Fahrenheit equivalent of this is: 88.1 F
(First original temperature) - (this temperature) is -31.1167 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 111.1 F and the second is 44.4 C
56
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( myX + point2.getX(), myY + point2.getY() );
return result;
}
57
58
Download