Zenon wrote:

Folks,

I am having a terrible time overloading operators. I have tried what

I thought was the correct way, I tried the cheating (friend

declarations), all to no avail. Sorry for posting tons of code but I

really need help.

And supplied his source code for a class Rational.

David B. Held replied: I don't know any psychics, and most people aren't going to simply

try out the code without some idea of what is wrong.

Well, a bunch of things are wrong :-). First, it doesn't compile. My advice

here: heed the compiler's error messages; they are usually specific and accurate.

Here is a number of specific points.

I assume your code should be split into two files, "Rational.hpp" and

"Rational.cc". (Next time, please indicate.) I added a little sample program

that uses a few of your operators. Make sure to write a real test program that

uses EVERY operator. It will look lengthy, but it's essential.

Check out this function,

Rational::string() // Typecast to string

{

return (char (numerator) + char(" / ") + char (denominator)) ;

}

First, every function needs a return type. I made it int. Why? It computes the

sum of three numbers: the numerator, the not very predictable address of the

string literal, and the denominator. They are cast to char, but before adding

them, integral promotion brings them back to int. BTW, this curious computation

is probably not what you wanted, and certainly NOT a typecast to string. And

casting the address to char still gives a warning.

Usually operator<<(std::ostream&, ...) returns a reference to the stream. For

convenience and convention, comply. You'll be able to write, e.g.,

os << "x = " << x << std::endl;

Also, write to the stream passed in, NOT cout.

I don't think the "const" qualifier matters in a return by value, as in your

binary operators +, -, *, /. I took it out. (In contrast, returning a const vs.

non-const reference is an important distinction.)

The constructor taking two ints contains this statement:

cout << "constructor numerator " + num ;

The numerator is added to a pointer to the first character of the c-style string

literal, yielding a pointer to another character. So if num is 4, we get a char*

that prints as "tructor numerator". If num is large or negative, worse may

happen. This is not the way to do string concatenation. I guess what was inteded

is a debug statement:

std::cerr << "constructor: numerator = " << num << std::endl;

But I left this one.

As I said before, omit "Rational::" qualifiers inside the class defintion.

Also, limit your lines to 80 characters. And prevent your news poster from

wrapping them shorter.

Lots of code in /* ... */ makes your source harder to read. Delete it.

Here's the output from the sample program (code below):

uctor numerator nstructor numerator a = 6 / 8; b = 2 / 3

onstructor numerator onstructor numerator onstructor numerator onstructor\

numerator c = 1 / 1; a-b = 1 / 12; a b = 1 / 2; a/b = 1 / 1

So, subtraction and multiplication seem fine in this example. Addition and

division need work. Lots to do!

Hoping this gets you started, Zenon

Christian

//------ t_rational.cc

#include "Rational.hpp"

#include <iostream>

int main() {

Rational a(6,8), b(2,3), c;

std::cout << "a = " << a << "; b = " << b << std::endl;

c = a + b;

std::cout << "c = " << c << "; a-b = " << a-b << "; a b = " << a*b

<< "; a/b = " << a/b << std::endl;

}

//----- Rational.hpp

#ifndef Rational__hpp

#define Rational__hpp

#include<iostream>

#include<iomanip>

#include <cstring>

#include <cmath>

#include <sstream>

#include <fstream>

class Rational

{

// Define data members

int numerator;

int denominator;

// define function prototypes

public:

Rational(int num, int denom); // Creates a fraction

Rational(); // Default constructor

~Rational(); // Default destructor

void signAdjuster();

int reducer(); // helper function to reduce fracion if possible

// helper function to reduce fracion if possible

int reducer(int numerator, int denominator);

Rational operator += (const Rational& fraction);

Rational operator -= (const Rational& fraction);

Rational operator *= (const Rational& fraction);

Rational operator /= (const Rational& fraction);

friend std::ostream& operator << (std::ostream& os,

const Rational& fraction);

friend Rational operator + (const Rational& lhs, const Rational& rhs);

friend Rational operator - (const Rational& lhs, const Rational& rhs);

friend Rational operator * (const Rational& lhs, const Rational& rhs);

friend Rational operator / (const Rational& lhs, const Rational& rhs);

operator double(); // Typecast to double

int string(); // Typecast to string -- actually to a funny int

};

std::ostream& operator<< (std::ostream& os, const Rational& fraction);

std::istream& operator>> (std::istream& is, Rational& fraction);

#endif

//----- Rational.cc

#include <cstring>

#include <cmath>

#include<iostream>

#include <fstream>

#include <vector>

#include <iomanip>

#include <sstream>

#include "Rational.hpp"

using namespace std;

Rational::Rational(int num, int denom)

// Set a fractions numerator and denominator

{

numerator = num;

denominator = denom;

cout << "constructor numerator " + num ;

signAdjuster();

}

Rational::Rational() {} // Default constructor

Rational::~Rational() {} // Destructor

Rational Rational::operator += (const Rational& fraction)

{

int tempNumOne = 0;

int tempNumTwo = 0;

int tempDenom = 0;

tempNumOne = fraction.numerator * denominator;

tempDenom = fraction.denominator * denominator;

tempNumTwo = numerator * fraction.denominator;

numerator = tempNumOne + tempNumTwo;

denominator = tempDenom;

int divisor = reducer ();

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return *this;

}

Rational Rational::operator -= (const Rational& fraction)

{

int tempNumOne = 0;

int tempNumTwo = 0;

int tempDenom = 0;

tempNumOne = fraction.numerator * denominator;

tempDenom = fraction.denominator * denominator;

tempNumTwo = numerator * fraction.denominator;

numerator = tempNumOne - tempNumTwo;

denominator = tempDenom;

int divisor = reducer ();

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return *this;

}

Rational Rational::operator *= (const Rational& fraction)

{

numerator *= fraction.numerator;

denominator *= fraction.denominator;

int divisor = reducer ();

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return *this;

}

Rational Rational::operator /= (const Rational& fraction)

{

numerator *= fraction.denominator;

denominator *= fraction.numerator;

int divisor = reducer ();

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return *this;

}

Rational operator + (const Rational& fractionLeft,

const Rational& fractionRight)

{

int tempNumOne = 0;

int tempNumTwo = 0;

int tempDenom = 0;

tempNumOne = fractionLeft.numerator * fractionRight.denominator;

tempDenom = fractionLeft.denominator * fractionRight.denominator;

tempNumTwo = fractionRight.numerator * fractionLeft.denominator;

int numerator = tempNumOne + tempNumTwo;

int denominator = tempDenom;

Rational obj;

int divisor = obj.reducer(numerator, denominator);

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return Rational(numerator, denominator);

}

Rational operator - (const Rational& fractionLeft,

const Rational& fractionRight)

{

int tempNumOne = 0;

int tempNumTwo = 0;

int tempDenom = 0;

tempNumOne = fractionLeft.numerator * fractionRight.denominator;

tempDenom = fractionLeft.denominator * fractionRight.denominator;

tempNumTwo = fractionRight.numerator * fractionLeft.denominator;

int numerator = tempNumOne - tempNumTwo;

int denominator = tempDenom;

Rational obj;

int divisor = obj.reducer(numerator, denominator);

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return Rational(numerator, denominator);

}

Rational operator * (const Rational& fractionLeft, const

Rational& fractionRight)

{

int numerator = fractionLeft.numerator * fractionRight.numerator;

int denominator = fractionLeft.denominator *

fractionRight.denominator;

Rational obj;

int divisor = obj.reducer(numerator, denominator);

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return Rational(numerator, denominator);

}

Rational operator / (const Rational& fractionLeft, const

Rational& fractionRight)

{

int numerator = fractionLeft.numerator * fractionRight.denominator;

int denominator = fractionLeft.denominator *

fractionRight.numerator;

Rational obj;

int divisor = obj.reducer(numerator, denominator);

if (divisor != 1)

{

numerator /= divisor;

denominator /= divisor;

}

return Rational(numerator, denominator);

}

std::ostream& operator << (std::ostream& os, const Rational& fraction)

{

return os << fraction.numerator << " / " << fraction.denominator;

}

Rational::operator double() // Typecast to double

{

return double (numerator/denominator);

}

int Rational::string() // Typecast to string.

{

// sum of the codes of three characters making little sense.

return (char (numerator) + char(" / ") + char (denominator)) ;

}

int Rational::reducer() // helper function to reduce fraction if possible

{

int small = 0;

int num = 0;

int den = 0;

num = numerator;

den = denominator;

if (num == 0)

return den;

if (den == 0)

return num;

// Only absolute value is important

if (den < 0)

den = den * -1;

if (num < 0)

num = num * -1;

// Smaller of the two becomes small

if (num > den)

small = den;

else

small = num;

// Continue till no remainder

while (num % small != 0 || den % small != 0)

{

if (num > small)

{

num = num - (num % small);

small = num;

}

else

{

den = den - (den % small);

small = den;

}

}

// Return thr divisor which leaves no remainder

return small;

}

int Rational::reducer(int numerator, int denominator)

// helper function to reduce fraction if possible

{

int small = 0;

int num = 0;

int den = 0;

num = numerator;

den = denominator;

if (num == 0)

return den;

if (den == 0)

return num;

// Only absolute value is important

if (den < 0)

den = den * -1;

if (num < 0)

num = num * -1;

// Smaller of the two becomes small

if (num > den)

small = den;

else

small = num;

// Continue till no remainder

while (num % small != 0 || den % small != 0)

{

if (num > small)

{

num = num - (num % small);

small = num;

}

else

{

den = den - (den % small);

small = den;

}

}

// Return thr divisor which leaves no remainder

return small;

}

// Make sure that numerator has negative sign if applicable

void Rational::signAdjuster()

{

if (numerator >= 0 && denominator < 0)

// Positive numerator, negative denominator

{

numerator *= -1;

denominator *= -1;

}

if (numerator < 0 && denominator < 0)

// Negative numerator, negative denominator

{

numerator *= -1;

denominator *= -1;

}

}