C++ error with operator overloading - c++

I am trying to make program that uses operator overloading to do basic math operations on rational numbers. I keep getting an errors in the functions where it says i must have an arithmetic of enum type. Also I get an error istream where it says that the numerator and denominator are undefined.
Here is the header file:
#ifndef rational_H
#define rational_H
#include <iostream>
using namespace std;
class Rational
{
friend ostream & operator<<(ostream & , const Rational &);
friend istream & operator<<(istream & , const Rational &);
public:
// default constructor
Rational(int = 0, int = 1);
// overload operators for "normal" operation
Rational operator+(const Rational&);
Rational operator-(const Rational&);
Rational operator*(const Rational&);
Rational operator/(const Rational&);
operator double();
// overload relational operators for "normal" operation
bool operator>(const Rational&) const;
bool operator<(const Rational&) const;
bool operator>=(const Rational&) const;
bool operator<=(const Rational&) const;
bool operator==(const Rational&) const;
bool operator!=(const Rational&) const;
protected:
int *numerator;
int *denominator;
void reduction(void);
};
#endif
// this part of code is from my rational cpp file//
// default constructor//
Rational::Rational( int n, int d )
{
*numerator =1 ;
// sets numerator
if(d == 0)
d = 1; // If denominator is zero then set to one.
*denominator = 0;
// sets denominator
reduction(); // store the fraction in reduced form
}
// all the other operators have the same error as well//
Rational Rational::operator-(const Rational&a)
{
Rational sub;
sub.numerator = *this->numerator * a.denominator -//the error is with the 'a'needs to be an arithmetic type or enum type//
*this->denominator * a.numerator;
sub.denominator = *denominator * a.denominator;
sub.reduction();
return sub;
}
//also the istream part has an error where the denominator and numerator is underfined as well//
istream& operator >> ( istream& inputStream, Rational& rnum )
{
inputStream>>rnum.*numerator;//numerator and denmoinator undefined for some reason//
inputStream.ignore(1);
inputStream>>rnum.*denominator;
return inputStream;
}

There are multiples small errors in your code.
First of all you should not be using pointers for these members, it does not bring any advantages.
But as you chose this way, you have to dereference them each time you want to read or update them, which hasn't be done in your operator- implementation, and incorrectly in your operator>> implementation (the asterisk needs to be put before the whole expression).
Next error in the code you provided, you marked as friend operator<<(istream & , const Rational &) in your class definition, but it should have been operator>>. And this declaration needs to match the definition that appears next (i.e., remove the const of the second argument, which obviously has to be mutated).
And, last but not least, the undefined behavior caused by all the dereferencing of you uninitialized pointers…

This is probably a copy and past error. The line
friend istream & operator<<(istream & , const Rational &);
should be
friend istream & operator>>(istream & , Rational &);
Your implementation later on in the file has:
istream& operator >> ( istream& inputStream, Rational& rnum )
{
...
}
It matches the second declaration, not the first one.

Related

No operator "=" matches these operands. I have overloaded it but it doesn't seem to be working properly

I have overloaded the "=" operator to accept objects of my class rational, but it does not seem to be working. Here are my headers and my class definition
#include <iostream>
#include <assert.h>
#include <fstream>
using namespace std;
class rational {
public:
rational();
rational(int numerator, int denominator);
rational(const rational& r);
int numerator() const;
int denominator() const;
const rational& operator = (const rational& rhs); //this is what I'm having issues with
private:
int myNumerator, myDenominator;
void reduce();
};
Here is my overload implementaion (which I have below main):
const rational& rational::operator = (const rational& rhs) {
if (*this != rhs) { //added asterisk, otherwise operator would not work
myNumerator = rhs.numerator();
myDenominator = rhs.denominator();
}
return *this;
}
And below that I am having issues using the "=" operator in the following implementation:
istream& operator>>(istream& is, const rational& r) {
char divisionSymbol;
int numerator = 0, denominator = 0;
is >> numerator >> divisionSymbol >> denominator;
assert(divisionSymbol == '/');
assert(denominator != 0);
rational number(numerator, denominator);
r = number; /* Error: no operator matches these operands (more specifically no operator found
which takes a left-hand operand of type 'const rational') but I am unsure how to fix that as the
assignment operator only takes one parameter (unless I am mistaken)*/
return is;
}
I cannot for the life of me think of what is not working, possibly a syntax issue? And the professor I have is very old-school so possibly an outdated practice? Any tips would be appreciated.
Problem is not with '=' operator overloading function. Issue is with '>>' operator overloading function. You declared r as const reference parameter and you are trying to modify it by assigning 'number' object to it.
If you want to modify 'r', you should declare 'r' as just reference as below.
istream& operator>>(istream& is, rational& r)

Returning a vector containing objects by reference

I am trying to write a function that returns a vector consisting of n random Fractions. I am getting a strange error telling me to "see reference to function template instantiation, and that "class Fraction: no copy constructor available or copy constructor is declared 'explicit'". Any help is greatly appreciated.
Here is the code I have written:
vector<Fraction> & genV(int n) {
vector<Fraction> temp;
for (int i = 0; i < n; i++) {
int n, d;
n = rand() % (100);
d = rand() % (100);
// create a new random fraction
Fraction *tempFraction = new Fraction(n, d);
// push new fraction to vector
temp.push_back(*tempFraction);
}
return temp;
}
Here is the header file:
#ifndef FRACTION_H
#define FRACTION_H
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class Fraction {
private:
int *numerator;
int *denominator;
public:
int getNumerator();
int getDenominator();
void reduce();
int gcd(int, int);
// constructors
Fraction(); // default c'tor
Fraction(int n); // create a fraction of n/1
Fraction(int n, int m); // Fraction n/m
Fraction(Fraction & other); // copy c'tor
~Fraction(); // destructor
Fraction & operator=(Fraction & rhs);
// overload assignment operator
Fraction & operator+(Fraction &rhs);
Fraction & operator-(Fraction &rhs); // overload binary operator -
Fraction & operator-(); // overload unary operator - (negative)
Fraction & operator *(Fraction &rhs);
Fraction & operator/(Fraction & rhs);
Fraction & operator++();// overload prefix ++
Fraction & operator++(int); // overload postfix ++
Fraction & operator--();// overload prefix --
Fraction & operator--(int); // overload postfix --
// overload relational operators
bool operator >(Fraction & rhs); // return true if *this > rhs , false elsewise
bool operator == (Fraction & rhs);
bool operator < (Fraction & rhs);
bool operator !=(Fraction &rhs);
Fraction & operator+=(Fraction & rhs);
Fraction & operator-=(Fraction & rhs);
Fraction & operator*=(Fraction & rhs);
Fraction & operator/=(Fraction & rhs);
string toString();
char * toCstring();
bool isZero(); // return true if *this is zero
int power(int base, int exp);
Fraction & operator^(int n);
friend istream & operator >> (istream & in, Fraction & rhs);
friend ostream & operator << (ostream & out, Fraction & rhs);
};
#endif
this Fraction(Fraction & other); // copy c'tor isn't a copy constructor.
this Fraction(const Fraction & other); // copy c'tor is a copy constructor.
And the reason why you aren't getting the default one is because you disabled the automatic generation of it with the other declarations.

header file for rational class : no type error

I have built a rational class, here is my .h file:
#ifndef RATIONAL_H
#define RATIONAL_H
#include <iostream>
using std::istream;
using std::ostream;
class Rational
{
public:
Rational();
Rational(int n);
Rational(int n, int d);
Rational(const Rational& other);
~Rational();
Rational operator+(const Rational& other);
Rational operator-(const Rational& other);
Rational operator*(const Rational& other);
Rational operator/(const Rational& other);
Rational operator+(int n);
Rational operator-(int n);
Rational operator*(int n);
Rational operator/(int n);
Rational& operator=(const Rational& other);
bool operator==(const Rational& other);
bool operator!=(const Rational& other);
bool operator>=(const Rational& other);
bool operator<=(const Rational& other);
bool operator<(const Rational& other);
bool operator>(const Rational& other);
bool operator==(int n);
bool operator!=(int n);
bool operator>=(int n);
bool operator<=(int n);
bool operator<(int n);
bool operator>(int n);
friend istream& operator>>(istream& is, Rational &r);
friend ostream& operator<<(ostream& is, Rational &r);
private:
int
num,
den;
};
#endif // RATIONAL_H
I am getting multiple errors, my main being:
include\Rational.h|8|error: ISO C++ forbids declaration of 'Rations'
with no type [-fpermissive]|
include\Rational.h|41|error: 'istream' does not name a type|
include\Rational.h|42|error: 'ostream' does not name a type|
and the rest in my main file (which are all cause because I tried to use >> and <<). I have searched for hours now, found similar problems, tried multiple solutions I don't want to shoot in the dark, I want to know what the problem is and why. For the record here is what I have for Rations in my implementation file:
Rational::Rations(int n)
{
num = n;
den = 1;
}
Let me know if my complete cpp implementation file or main is needed to solve this.. Also, I am using codeblocks, I have added include into my compiler in build options.
You seem to intend that Rations(int) should be a constructor for you class, but the name of the constructor must be the same as the name of the class:
Rational::Rational(int n)
If it was not a typo then I have no idea why you changed Rational to Rations.
As for istream and ostream, your class refers to them, but you haven't declared them-- the compiler has no idea what you're talking about. You must either include the proper headers in your header file (above the class definition):
#include <istream>
using std::istream;
using std::ostream;
or, if you're going to be really strict about it, use forward declaration above the class definition:
class istream;
class ostream;
and then put the #include directives in your source code, above the function definitions.
Constructors have the same name as the class and have no return type.
Your function Rations is spelled differently and either needs a return type of void (not returning a value) or it needs to return a value.

New to c++ and Overloading operators, unsure how to use the function

Hi I am rather new to C++, I have just started learning it after learning some Java basics.
I have pre-existing code were it has overloaded the >> operator, however after watching many tutorials and trying to understand the issue, I thought I would ask here.
Rational cpp file:
#include "Rational.h"
#include <iostream>
Rational::Rational (){
}
Rational::Rational (int n, int d) {
n_ = n;
d_ = d;
}
/**
* Creates a rational number equivalent to other
*/
Rational::Rational (const Rational& other) {
n_ = other.n_;
d_ = other.d_;
}
/**
* Makes this equivalent to other
*/
Rational& Rational::operator= (const Rational& other) {
n_ = other.n_;
d_ = other.d_;
return *this;
}
/**
* Insert r into or extract r from stream
*/
std::ostream& operator<< (std::ostream& out, const Rational& r) {
return out << r.n_ << '/' << r.d_;
}
std::istream& operator>> (std::istream& in, Rational& r) {
int n, d;
if (in >> n && in.peek() == '/' && in.ignore() && in >> d) {
r = Rational(n, d);
}
return in;
}}
Rational.h file:
#ifndef RATIONAL_H_
#define RATIONAL_H_
#include <iostream>
class Rational {
public:
Rational ();
/**
* Creates a rational number with the given numerator and denominator
*/
Rational (int n = 0, int d = 1);
/**
* Creates a rational number equivalent to other
*/
Rational (const Rational& other);
/**
* Makes this equivalent to other
*/
Rational& operator= (const Rational& other);
/**
* Insert r into or extract r from stream
*/
friend std::ostream& operator<< (std::ostream &out, const Rational& r);
friend std::istream& operator>> (std::istream &in, Rational& r);
private:
int n_, d_;};
#endif
The function is from a pre-existing class called Rational which takes two ints as parameters. Here is the function to overload >> :
std::istream& operator>> (std::istream& in, Rational& r) {
int n, d;
if (in >> n && in.peek() == '/' && in.ignore() && in >> d) {
r = Rational(n, d);
}
return in;
}
And I'm trying to use it like this, after seeing a few tutorials. (The error I am getting is "Ambiguous overload for operator>> in std::cin>>n1 :
int main () {
// create a Rational Object.
Rational n1();
cin >> n1;
}
Like I said I'm new to this whole overloading operators thing, and figure someone here would be able to point me in the right direction on how to use this function.
Change Rational n1(); to Rational n1;. You've ran into the most vexing parse. Rational n1(); does not instantiate a Rational object, but declares a function named n1 which returns a Rational object.
// create a Rational Object.
Rational n1();
this doesn't create new object but declares a function taking no arguments and returning Rational
you probably meant
// create a Rational Object.
Rational n1;
cin>>n1;

Way of overloading operator without changing original values?

I'm wondering if you can overload an operator and use it without changing the object's original values.
Edited code example:
class Rational{
public:
Rational(double n, double d):numerator_(n), denominator_(d){};
Rational(){}; // default constructor
double numerator() const { return numerator_; } // accessor
double denominator() const { return denominator_; } // accessor
private:
double numerator_;
double denominator_;
};
const Rational operator+(const Rational& a, const Rational& b)
{
Rational tmp;
tmp.denominator_ = (a.denominator() * b.denominator());
tmp.numerator_ = (a.numerator() * b.denominator());
tmp.numerator_ += (b.numerator() * a.denominator());
return tmp;
}
I made the accessors const methods, but I'm still getting a privacy error for every tmp.denominator_ / numerator_.
Maybe I'm missing something, but why don't you just take out the code that modifies the arguments?
const Rational Rational::operator+(Rational& num)
{
Rational tmp;
tmp.denominator_ = (denominator_*num.denominator_);
//numerator_*=num.denominator_;
//num.numerator_*=denominator_;
tmp.numerator_ = (numerator_+num.numerator_);
return tmp;
}
This would be caught earlier by being const-correct.
That means your function signature should be this:
Rational Rational::operator+(const Rational& num) const
Then you will get errors because you are modifying const objects. The way your operators are written now is generally considered incorrect.
When you add 2 + 3, neither 2 nor 3 changes: they are const.
Edit
Sorry, I missed the actual math part. Here are a few things:
As a member function (what I have above), do this:
// Note that I use lhs and rhs to refer to the left-hand
// and right-hand sides of an operation. As a member function
// my left-hand side is implicitly `this`.
Rational Rational::operator+(const Rational& rhs) const
{
Rational temp;
temp.denominator_ = (denominator() * rhs.denominator());
temp.numerator_ = (numerator() * rhs.denominator());
temp.numerator_ += (denominator() * rhs.numerator());
return temp;
}
As a global function, do this:
Rational operator+(const Rational& lhs, const Rational& rhs)
{
Rational temp;
temp.denominator_ = (lhs.denominator() * rhs.denominator());
temp.numerator_ = (lhs.numerator() * rhs.denominator());
temp.numerator_ += (lhs.denominator() * rhs.numerator());
return temp;
}
The issue here is you'll get access violations: your member variables are private to the class. You need to let the compiler know that it is okay if this function handles your class's private variables by making the function a friend of the class:
class Rational
{
public:
friend Rational operator+(const Rational& lhs, const Rational& rhs);
}
What you're looking for are the "binary" addition and subtraction operators:
const Rational operator+(const Rational& A, const Rational& B)
{
Rational result;
...
return result;
}
update (in response to new code and comments):
You are getting that error because your accessor functions are not declared as constant functions, so the compiler has to assume that they might modify the original object. Change your accessors as follows, and you should be good to go:
double numerator() const { return numerator_; }
double denominator() const { return denominator_; }
update
To properly handle privacy issues, you should declare the binary operator+ function as a friend of the Rational class. Here is how it would look:
class Rational {
public:
Rational(double n, double d):numerator_(n), denominator_(d) {};
Rational() {}; // default constructor
double numerator() const { return numerator_; } // accessor
double denominator() const { return denominator_; } // accessor
friend Rational operator+(const Rational& A, const Rational& B);
private:
double numerator_;
double denominator_;
};
const Rational operator+(const Rational& a, const Rational& b)
{
Rational result;
result.denominator_ = (a.denominator_ * b.denominator_);
result.numerator_ = (a.numerator_ * b.denominator_);
result.numerator_ += (b.numerator_ * a.denominator_);
return result;
}
no .. you have to rewrite + and - .. it's not that hard. Then change the signatures to
const Rational Rational::operator+(Rational& num) const
const Rational Rational::operator-(Rational& num) const
that way the compiler will let you know if you are modifying your object.
Since your class already provides accessors to the numerator and denominator, and it has a public constructor, there is no need to use any friends. You can overload operator+ as follows:
const Rational operator+(const Rational& rhs, const Rational& lhs)
{
double newNumerator = rhs.numerator() * lhs.denominator() +
rhs.denominator() * lhs.numerator();
return Rational(newNumerator, rhs.denominator() * lhs.denominator());
}
In response to some of the other answers:
Everything about this question is exactly answered by Item 24 of Effective C++ (Third Edition). In this item, Scott Meyers shows that, in cases dealing with numerical types where you want to support implicit conversion in an intuitive manner, it is best to use a non-member non-friend function.
Say your Rational class had the following constructor:
Rational::Rational(double numerator = 0, double denominator = 1);
In this case, if operator+ were a member function, trying to do mixed mode arithmetic would work only half the time:
Rational oneHalf(1, 2);
oneHalf + 2; // works
2 + oneHalf; // error!
In the second example, operator+ for integers is called. The way to fix this is to make operator+ for Rationals a non-member function as shown above.
If you have access to Effective C++, you should also check out Item 23: Prefer non-member non-friend functions to member functions.
I prefer to implement operator+ in terms of operator+=. Then clients get to choose if they want a temp copy or not. Also operator+= is more natural as a member function so it has access to the private parts.
class Rational {
public:
Rational(double n, double d):numerator_(n), denominator_(d) {};
Rational() {}; // default constructor
double numerator() const { return numerator_; } // accessor
double denominator() const { return denominator_; } // accessor
Rational & operator+=(const Rational& b) {
denominator_ *= b.denominator_);
numerator_ *= (b.denominator_);
numerator_ += (b.numerator_ * denominator_);
return *this;
}
private:
double numerator_;
double denominator_;
};
const Rational operator+(const Rational& a, const Rational& b)
{
Rational result(a);
result += b;
return result;
}
However the easiest way to implement operator overloading is to use the boost operators library. Then you implement the minimum set of operators and boost take care of the rest and all the gotchas (including wintermute's example of 2 + oneHalf.