I have tried to add more features to already given class(the answer of #Aak) in the problem: How to output fraction instead of decimal number?
for printing fractions in numerator / denominator .
First of all, the given code was not working without any change in the code. Then I made it working after making some changes. However, my implementation gives me a wrong output.
for example:
input: A = 3;
B = 3;
Output: 9/1
9
instead of: 1
here is the complete implementation:
#include <iostream>
/********************** Rational class **********************************/
class Rational
{
private:
int m_numerator, m_denominator;
private:
inline void simplificate()
{
int commondivisor = 1;
for(int i=2;i<= std::min(abs(m_numerator), abs(m_denominator));i++)
if( m_numerator%i == 0 && m_denominator%i == 0 )
commondivisor = i;
m_numerator /= commondivisor;
m_denominator /= commondivisor;
}
public:
Rational() // Defualt
:m_numerator(1), m_denominator(1)
{}
Rational(const int& num, const int& den=1) // Parameterized
:m_numerator(num), m_denominator(den)
{}
Rational(const Rational& other) // Copy
:m_numerator(other.m_numerator), m_denominator(other.m_denominator)
{}
/*Rational(Rational&& other) // Move
:m_numerator(other.m_numerator), m_denominator(other.m_denominator)
{}*/
~Rational(){}
Rational& operator/ (const int& divisor)
{
m_denominator *= divisor;
simplificate();
return *this;
}
Rational& operator/ (const Rational &divisor)
{
m_numerator *= divisor.m_numerator;
m_denominator *= divisor.m_denominator;
simplificate();
return *this;
}
const double getrealformat()const
{
return static_cast<double>(m_numerator)/
static_cast<double>(m_denominator);
}
friend double operator/ (Rational& obj, const int& divisor);
friend void printRational(Rational& obj, const int& A, const int& B);
friend void printRational(Rational& obj, const int&& A, const int&& B);
};
/************************** Friend functions ********************************/
double operator/ (Rational& obj, const int& divisor)
{
obj.m_denominator *= divisor;
obj.simplificate();
return obj.getrealformat();
}
void printRational(Rational& obj, const int& A, const int& B) // lvalue
{
Rational r1(A), r2(B);
obj = r1/r2;
std::cout<<obj.m_numerator<<'/'<<obj.m_denominator<<std::endl;
std::cout<<obj.getrealformat()<<std::endl;
}
void printRational(Rational& obj, const int&& A, const int&& B) // rvalue
{
Rational r1(A), r2(B);
obj = r1/r2;
std::cout<<obj.m_numerator<<'/'<<obj.m_denominator<<std::endl;
std::cout<<obj.getrealformat()<<std::endl;
}
/*****************************************************************************/
int main()
{
Rational obj;
printRational(obj, 3,3);
return 0;
}
Question - 1: the logic looks fine, but I don't know why I am getting the wrong answer. Can anybody find the problem?
Question - 2: I have written "Move" constructor for the class, which you can find in the commented section. However, I could not use it because of following error:
D:\Programming\C++\CPP Programs\Class - Fractions\Class - Fractions.cpp|70|error: use of deleted function 'Rational& Rational::operator=(const Rational&)'|
D:\Programming\C++\CPP Programs\Class - Fractions\Class - Fractions.cpp|77|error: use of deleted function 'Rational& Rational::operator=(const Rational&)'|
(whenever it has been called the moved object/instance is destroyed, to my knowledge.)
can anybody help me to implement the Move constructor for this class?
Look your operator/()
Rational& operator/ (const Rational &divisor)
{
m_numerator *= divisor.m_numerator;
m_denominator *= divisor.m_denominator;
simplificate();
return *this;
}
This code is correct for operator*(), not for operator/().
Maybe
m_numerator *= divisor.m_denominator;
m_denominator *= divisor.m_numerator;
But is worse that you're operator/() modify the object.
Your code (corrected switching numerator and denominator) should be correct for operator/=(), not for operator/() that should return a new object.
I suggest something as follows
Rational& operator/= (const Rational &divisor)
{
m_numerator *= divisor.m_denominator;
m_denominator *= divisor.m_numerator;
simplificate();
return *this;
}
friend Rational operator/ (Rational A, Rational const & B);
and, outside the class,
Rational operator/ (Rational A, Rational const & B)
{ return A/=B; }
Regarding question 2 ("I have written "Move" constructor for the class, [...]However, I could not use it because of following error"), you can see in this page that
A implicitly-declared copy assignment operator for class T is defined as deleted if any of the following is true:
T has a user-declared move constructor;
T has a user-declared move assignment operator.
So, when you define the move contructor, you delete the implicit copy operator.
You can solve the problem adding
Rational & operator= (Rational const &) = default;
reactivating the implicit copy constructor
Related
I was reading through the third edition of Effective C++ and I was surprised that a snippet on page 18 compiles. Here is a snippet inspired from that (compiler explorer link):
struct Rational {
Rational(int numer, int denom): numer(numer), denom(denom) {}
int numer, denom;
};
Rational operator*(const Rational& lhs, const Rational& rhs) {
return Rational(lhs.numer * rhs.numer, lhs.denom * rhs.denom);
}
int main() {
Rational a(1,2), b(3,4), c(5,6);
a*b = c;
}
From my understanding, a*b is an r-value, and hence have no location in memory. How is it possible that an assignment operator can be called on an r-value?
a*b = c; calls the assignment operator on the Rational returned by a * b. The assignment operator generated is the same as if the following were defined:
Rational& Rational::operator=(const Rational&) = default;
There is no reason why this shouldn't be callable on a temporary Rational. You can also do:
Rational{1,2} = c;
If you wanted to force the assignment operator to be callable only on lvalues, you could declare it like this, with a & qualifier at the end:
Rational& operator=(const Rational&) &;
"a*b is an r-value, and hence have no location in memory" it is not quite right.
I add prints. The comments are the prints for each line of code
#include <iostream>
using namespace std;
struct Rational {
Rational(int numer, int denom) : numer(numer), denom(denom) {
cout << "object init with parameters\n";
}
Rational(const Rational& r)
{
this->denom = r.denom;
this->numer = r.numer;
cout << "object init with Rational\n";
}
~Rational() {
cout << "object destroy\n";
}
int numer, denom;
};
Rational operator*(const Rational& lhs, const Rational& rhs) {
cout << "operator*\n";
return Rational(lhs.numer * rhs.numer, lhs.denom * rhs.denom);
}
int main() {
Rational a(1, 2), b(3, 4), c(5, 6); // 3x object init with parameters
cout << "after a, b, c\n"; // after a, b, c
Rational d = a * b = c; // operator*, object init with parameters, object init with Rational, object destroy
cout << "end\n"; // end
// 4x object destroy
}
In the line Rational d = a * b = c; d is equal to c. This line call operator* function, that call the object init with parameters constructor. After that c object is copied to d object by calling copy constructor.
If you write the line: Rational d = a = c; // d == c // print only: object init with Rational the compiler assign the d object only to the last assign (object c)
Rational operator*(const Rational& lhs, const Rational& rhs) {
cout << "operator*\n";
return Rational(lhs.numer * rhs.numer, lhs.denom * rhs.denom);
}
operator *() returns an object of type Rational and that is the l value.
I have a class similar to this:
class Frac
{
int numer;
int denom;
public:
Frac &simplify();
Frac(int &&num, int &&den) : numer { num }, denom { den }
{
simplify();
}
Frac operator*(const int &rhs)
{
Frac result = { numer * rhs, denom };
return result.simplify();
}
}
However, I don't like using the intermediate result when overloading *.
Ideally, I'd like to do something like this:
Frac operator*(const int &rhs)
{
return { numer * rhs, denom }.simplify();
}
but that doesn't work; it constructs an std::initializer_list<int> instead of a Frac and you can't call the member function. In C I would be able to do this with a compound literal but those are not available in standard C++.
How can I generate and return a result in one expression?
Since you are already calling simplify() in the constructor, all you need to call is the constructor by itself, and return the object it creates:
Frac operator*(const int &rhs)
{
return Frac(numer * rhs, denom);
}
If you decide later on to update the constructor to no longer call simplify(), you can still call simplify() explicitly on the object that is created by calling the constructor:
Frac operator*(const int &rhs)
{
return Frac(numer * rhs, denom).simplify();
}
I know what it means but in my situation I don't understand why my IDE yelling me about this.
Rational operator*(const Rational& that1, const Rational& that2)
{
Rational temp(that1);
temp.getNom() *= that2.getNom();
temp.getDenom() *= that2.getDenom();
return temp;
}
int Rational::getNom() const
{
return m_iNom / gcd(m_iNom, m_iDenom);
}
int Rational::getDenom() const
{
return m_iDenom / gcd(m_iNom, m_iDenom);
}
float Rational::gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
m_iNom & m_iDenom are private data members inside Rational class.
I'm getting 'expression must be a modifiable lvalue' at :
temp.getNom() *= that2.getNom();
temp.getDenom() *= that2.getDenom();
You cannot affect a value to a function or method return.
temp.getNom() *= that2.getNom(); is like temp.getNom() = temp.getNom() * that2.getNom();
It's like to write 2 = 2 * 3 and set 2 = 5 … no sense!
As the compiler says, you can't assign to the return value.
Even if you could assign to the return value, the member variables would be unaffected —
the accessors return the values of the member variables, not the actual variables.
The idiomatic way of doing this is to first implement operator *= as a member:
Rational& operator *= (const Rational& that)
{
m_iNom *= that.m_iNom;
m_iDenom *= that.m_iDenom;
return *this;
}
and then use that to implement *:
Rational operator*(const Rational& that1, const Rational& that2)
{
Rational result(that1);
result *= that2;
return result;
}
I'm doing a Little rational class for my Project and I overload all aritmethic operators. Well, when I try to overload operator= I have a Little and now I don't know if is my problem (i don't know how it Works) or problem of my wroten code (i wrote it bad) here's the code:
class rational{
public:
double& operator=(double& d){
d= this->num/this->den;
return d;
}
double& operator=(rational& r){
double d= r.num/r.den;
return d;
}
double& operator=(){
double d= this->num/this->den;
return d;
}
}
Ok, what's wrong? what's right? (i think that all is wrong haha)
My goal is do that:
int main(){
rational r(4, 5);
double d= r;
}
Can I do it? if yes, how?
You don't want an assignment operator for this purpose - you should instead overload a conversion operator; e.g.
class rational {
private:
int num;
int den;
public:
// ...
operator double() { return double(num) / double(den); }
};
This will allow
rational r(4, 5);
double d = double(r); // d = 0.8
The assignment operators should be used for changing the state of an existing object, if that's something you want to allow. You probably would not want to allow assignment of a double to a rational there is no unambiguous meaning for such an operation. However, you might want to provide helpers for assigning an int, say, in addition to the usual one for assigning another rational:
rational &operator=(const rational &rhs)
{
num = rhs.num;
den = rhs.den;
return *this;
}
rational &operator=(int rhs)
{
num = rhs;
den = 1;
return *this;
}
Here I think a user-defined conversion operator would be more appropriate.
class rational {
public:
rational( int iNum, int iDen ) : num( iNum ), den( iDen ) {}
// ...
operator double() { return (double)num / (double)den; }
private:
int num;
int den;
};
int main()
{
rational r( 1, 2 );
double n = r;
std::cout << r << std::endl; // output 0.5
return 0;
}
Here is a little live example to illustrate this : http://ideone.com/I0Oj66
About the copy assignment operator= :
A copy assignment operator of class T is a non-template non-static member function with the name operator= that takes exactly one parameter of type T.
The operator= is used to change an existing object.
You can use it for example to copy the state of another object :
rational &operator=( const rational &rhs )
{
num = rhs.num;
den = rhs.den;
return *this;
}
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.