Classes
The following header file, rational.h
, declares a class that
represents a rational number:
#ifndef RATIONAL_H
#define RATIONAL_H
class Rational {
private:
int numerator;
int denominator;
public:
// Constructs a rational number with value 0
Rational();
// Constructs a rational number with value n
Rational(int n);
// Constructs a rational number with value a/b
Rational(int a, int b);
// Inverts the rational number
void invert();
// Returns the value of the rational number as a real number
double value() const;
// Multiplies two rational numbers
Rational operator*(Rational) const;
// Divides two rational numbers
Rational operator/(Rational) const;
};
#endif
The member variables numerator
and denominator
represent the
numerator and denominator of the rational number, respectively.
This class could be used in an application file as follows.
#include <iostream>
#include <vector>
#include "rational.h"
using namespace std;
int main() {
Rational x(3, 4);
Rational y(1, 2);
cout << "x.value(): " << x.value() << '\n';
cout << "y.value(): " << y.value() << '\n';
y.invert();
cout << "y.value(): " << y.value() << '\n';
Rational z = x * y;
cout << "z.value(): " << z.value() << '\n';
z = x / y;
cout << "z.value(): " << z.value() << '\n';
Rational w(3);
cout << "w.value(): " << w.value() << '\n';
vector<Rational> v = {Rational(), Rational(1), Rational(-4, -2), w};
for (const Rational& q : v) {
cout << q.value() << ' ';
}
cout << '\n';
return 0;
}
The expected output would then be
x.value(): 0.75
y.value(): 0.5
y.value(): 2
z.value(): 1.5
z.value(): 0.375
w.value(): 3
0 1 2 3
Exercise 8.1
In the following exercise, assume that the implementations are contained in a separate file
rational.cpp
(in the same directory asrational.h
) prefaced by#include "rational.h"
(a) Implement the constructors
Rational::Rational
according to their specifications above. Refer to the source code of the application file and its output for examples of their usage.
Solution
Here is one possible solution.
Rational::Rational() { numerator = 0; denominator = 1; } Rational::Rational(int n) { numerator = n; denominator = 1; } Rational::Rational(int a, int b) { numerator = a; denominator = b; }
Alternative solution
Here is another possible solution, using member initializer lists.
Rational::Rational() : numerator {0}, denominator {1} {} Rational::Rational(int n) : numerator {n}, denominator {1} {} Rational::Rational(int a, int b) : numerator {a}, denominator {b} {}
(b) Implement the member function
Rational::invert
according to its specification above.Solution
Here is one possible solution.
void Rational::invert() { int temp = numerator; numerator = denominator; denominator = temp; }
(c) Implement the member function
Rational::value
according to its specification above.Solution
Here is one possible solution.
double Rational::value() const { double numerator_d = numerator; double denominator_d = denominator; return numerator_d / denominator_d; }
(d) Overload the operator
*
according to the specification above. Note that the right operand will be passed as the argument.Solution
Here is one possible solution.
Rational Rational::operator*(Rational other) const { return Rational(numerator * other.numerator, denominator * other.denominator); }
(e) Overload the operator
/
according to the specification above. Note that the right operand will be passed as the argument.
Solution
Here is one possible solution.
Rational Rational::operator/(Rational other) const { return Rational(numerator * other.denominator, denominator * other.numerator); }
Alternative solution
Here is another possible solution, assuming that
Rational::invert
andRational::operator*
have been defined as in parts (b) and (d).Rational Rational::operator/(Rational other) const { other.invert(); return *this * other; }
Pointers
Exercise 8.2
(a) What is the output of the following program?
#include <iostream> using namespace std; int main() { int i = 10; int j = 20; int* ptr = &i; ptr = &j; j = 30; cout << "i: " << i << '\n'; cout << "j: " << j << '\n'; cout << "*ptr: " << *ptr << '\n'; return 0; }
Solution
i: 10 j: 30 *ptr: 30
Notice that the statement
ptr = &j
makesptr
point toj
.
(b) What is the output of the following program?
#include <iostream> using namespace std; int main() { int i = 10; int j = 20; int& ref = i; ref = j; j = 30; cout << "i: " << i << '\n'; cout << "j: " << j << '\n'; cout << "ref: " << ref << '\n'; return 0; }
Solution
i: 20 j: 30 ref: 20
Notice that the statement
ref = j
does not makeref
refer toj
; it only copies the value ofj
to what is referred to byref
(namely,i
). Asref
still refers toi
, it is unaffected by the statementj = 30
.
Arrays
See Section 5.3 (Pointers and Arrays) in The C Programming Language. (The rest of the chapter is also an excellent reference!)