Date post: | 02-Jan-2016 |
Category: |
Documents |
Upload: | robert-cunningham |
View: | 215 times |
Download: | 1 times |
2
Objectives• To easily create new instances of the rational number
abstraction.• To manipulate rational numbers using arithmetic operations,
yielding new rational number results. • It should be possible to mix rationals and other arithmetic
quantities in the same expression. • It should be possible to assign a rational number value to a
rational number variable. • The modification forms of assignment should be supported.• To compare one rational number to another. • It should be possible to perform input and output operations
with rational numbers.
3
Example of Rational Numbers// probability one is 1 in 8rational p1 (1,8);
// probability two is 2 in 3rational p2 (2, 3);
// probably of both together is their productrational p3 = p1 * p2;
// probably of either independent is their sumrational p4 = p1 + p2;
// what is this probability?cout << "combined probability is " << p3 << endl;cout << "independent probability is " << p4 << endl
4
Definition of Operations on Rational Numbers
O p e r a t i o n C a l c u l a t i o n
d
c
b
a
db
cbda
d
c
b
a
db
cbda
d
c
b
a
db
ca
d
c
b
a
cb
da
b
a
b
a
d
c
b
a )()( cbda
d
c
b
a )()( cbda i f b > 0 , d > 0
5
// class rational// rational number data abstraction
class rational {public:
// constructorsrational () : top(0), bottom(1) { }rational (int t) : top(t), bottom(1) { }rational (int t, int b) : top(t), bottom(b) { normalize(); }rational (const rational & r) : top(r.top), bottom(r.bottom) { }// accesser functionsint numerator () const { return top; }int denominator () const { return bottom; }// assignmentsvoid operator = (const rational & r) {top = r.top; bottom = r.bottom;}void operator += (const rational &);// other operationsoperator double () const { return top / (double) bottom; }const rational & operator++() { top += bottom; return this; }const rational operator++(int);
private:int top; // data areasint bottom;void normalize (); // operation used internally
};
6
Interface and Implementation
• The code associated with a component is separated into two files. – The interface file describes how to use the component.
– The implementation file contains the actual code to perform the actions.
• The class description is divided into two parts.– Public: behaviors and data fields that users of the data
abstraction can access.
– Private: behavior and fields that are accessible only within the component and are off-limits to other users.
7
Constructors
• Every class should define a default constructor.• Use initializes whenever possible.• The declaration that uses an empty parentheses list is
not syntactically incorrect; simply not doing what the programmer expects.
• Every class should define a copy constructor.
8
Member Function
• An accessor function provides access to the internal state of an object.
left.numerator() * right.denominator() + right.numerator() * left.denominator()
• A function defined as part of the behavior of a class is called a member function.
• The const keyword in C++ is not the same as the final keyword in Java.
9
Operators
• In C++, operators can potentially have overloaded meanings.
• Requirement: the definition must not require arguments that match any existing definition.
• Can be achieved if one or both arguments are a new data type, since no existing definition can be using these types.
10
Operators
const rational operator + (const rational & left, const rational & right)
{// return sum of two rational numbersrational result (
left.numerator() * right.denominator() + right.numerator() * left.denominator(),
left.denominator() * right.denominator());return result;
}
• The address operator in the argument list indicates that the left and right values will be passed by reference.
11
Operators
• A list of prototypes for the arithmetic operations.
// prototypes for arithmetic operations, including unary negationconst rational operator + (const rational &, const rational &);const rational operator - (const rational &, const rational &);const rational operator * (const rational &, const rational &);const rational operator / (const rational &, const rational &);const rational operator - (const rational &);bool operator < (const rational &, const rational &);bool operator == (const rational &, const rational &);
12
Unary Negation Operator
const rational operator - (const rational & val)
{// return negation of argument valuereturn rational (- val.numerator(), val.denominator());
}
13
Comparison Operators
bool operator < (const rational & left, const rational & right)
{// less than comparison of two rational numbersreturn left.numerator() * right.denominator() <
right.numerator() * left.denominator();
}
bool operator == (const rational & left, const rational & right)
{return left.numerator() * right.denominator() ==
right.numerator() * left.denominator();
}
14
Increment and Decrement
• The variable this is a value in Java but is a pointer in C++.
class rational {...const rational & operator ++ () { top += bottom; return *this;}...
};
const rational rational::operator++ (int) {// increment fraction, but return original value, make clonerational clone(*this);top += bottom; // make changereturn clone; // return clone
}
15
Functions
• Functions cannot access the internal (private) structure of any class, unless declared as a friend.
const rational abs (const rational & num) {// return the absolute value of a rational numberint newtop;int newbottom = num.denominator();
// get non-negative numerator partif (num.numerator() < 0)
newtop = - num.numerator();else
newtop = num.numerator();// create and return resultreturn rational(newtop, newbottom);
}
16
Member Function Operators
void rational::operator += (const rational & right)
{// modify by adding right hand sidetop = top * right.denominator() + bottom *
right.numerator();
bottom *= right.denominator();
// normalize the result, ensuring lowest denominator form
normalize();
}
17
void rational::normalize() {// normalize rational by (a) moving sign to numerator :// b) making sure numerator and denominator have no common divisorsint sign = 1; // sign is 1 if non-negative, -1 if negativeif (top < 0) {
sign = -1;top = - top;
}if (bottom < 0) {
sign = - sign;bottom = - bottom;
}
// make sure we are not dividing by zeroif (bottom == 0)throw range_error("fraction with zero numerator");
// find greatest common divisor int d = gcd(top, bottom);
// move sign to top and divide by gcdtop = sign * (top / d);bottom = bottom / d;
}
18
Member Function Operators
try {... // computation involving rationals
} catch (range_error & e) {printf("got exception %s", e.what());
}
19
Conversion Operations
• Constuctors are also used implicitly.
rational x, y;...
x = y * 3;
• Temporary values can also be created directly by the programmer, by invoking the constructor as if it were an ordinary function.
x = y * rational(3, 4);
20
Conversion Operations
• Conversions the other direction, from an object type to another type, are defined using a conversion operator.
• A conversion operator is an operator whose name is a type.
class rational {...
operator double () const { return top / (double) bottom; }};
21
Conversion Operations
• Avoid cast if possible, but if unavoidable use a static or dynamic cast.
rational x(3, 4);cout << "3/4 of pi is " << (3.14 * double(x)) << '\n';
22
Input and Output Streams
• Output is easily accommodated by redefining the left shift operator <<, and providing a new meaning.
ostream & operator << (ostream & out, const rational & value)
{// print representation of rational number on // an output stream
out << value.numerator() << '/' << value.denominator();return out;
}
23
Input and Output Streams
• Predefined precedence is low enough to allow arithmetic expressions to appear in output without using parenthesis, as in:
cout << "a + b * c is " << a + b * c << '\n';
• The left shift operator with its conventional meaning can be used in anoutput statement, by surrounding it with parenthesis:
cout << " a left shift by 3 is " << (a << 3) << '\n';
24
Stream Input• A loop that would read values repeatedly
from the input until end of file could be written as:
while (cin >> intval) {// process intval...
}// reach this point on end of input...
• An easy way to remember, the stream I/O operations is to visualize them as arrows.
• The input operator, >> x, points data into x, whilethe output operator, << x, copies data out of x.
25
istream & operator >> (istream & in, rational & r) {// read a rational number from an input streamint t, b;// read the topin >> t;// if there is a slash, read the next numberchar c;in >> c;if (c == '/')
in >> b; // read bottom partelse {
in.putback(c);b = 1;
}// do the assignmentrational newValue(t, b);r = newValue;// return the streamreturn in;
}