Can you Avoid Multiple Operator Overloads for Mathematical Operators? - c++

Say I have a very simple Rational class like the one below:
class Rational
{
int numer;
int denom;
public:
Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
}
All well and good. Then say that I want to be able to multiply my Rational class with an integer, so I add another function to the class:
class Rational
{
int numer;
int denom;
public:
Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
void operator*(const int& other) { std::cout << "some math here\n"; }
}
Ok no big deal. Except that I can't actually do the following because the order of the parameters would be all wrong:
Rational mine(1, 2);
const Rational result = 2 * mine;
Ok, one more iteration and I have the following:
class Rational
{
int numer;
int denom;
public:
Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
void operator*(const int& other) { std::cout << "some math here\n"; }
friend void operator*(const int& other, const Rational& mine) { std::cout << "even more math here\n"; }
}
What I'm trying to find out is if there's a way that I can avoid having to write the same function twice for every mathematical operation that I'd want my class to support, just so that I can call it with the arguments in whatever order I want. This may well just be how you have to implement this sort of thing within C++'s type system, but it seems a tad annoying to have to add this boilerplate for every mathematical operation that you want your class to support.

The issue with having a single function is that the type of the left and right operands to * would vary (and you would have to use them differently).
This can be solved by fixing both of the argument types to Rational and creating an implicit conversion from an int x to Rational x/1 (which is probably desirable anyways). This way, in 2 * mine, the 2 will implicitly be converted to Rational(2, 1) * mine.
Here's an example:
class Rational
{
int numer;
int denom;
public:
// default argument of denom=1 allows implicit conversion from int
Rational(int numer, int denom = 1) : numer(numer), denom(denom) {}
friend Rational operator*(const Rational& l, const Rational& r) {
std::cout << "Rational(" << l.numer << ", " << l.denom
<< ") * Rational(" << r.numer << ", " << r.denom << ")\n";
// calculate and return result
}
friend Rational operator/(const Rational& l, const Rational& r) { /* ... */ }
friend bool operator==(const Rational& l, const Rational& r) { /* ... */ }
};

Related

complex number wrong output

I write this code with a class named Complex with the following methods:
a. Complex() // Default constructor returning 0
b. Complex(float im, float real)
c. float getImaginary() const
d. float getReal() const
e. Complex add(const Complex& rhs) const
f. Complex subtract(const Complex& rhs) const
g. Complex multiply(const Complex& rhs) const
#include <iostream>
using namespace std;
class Complex {
private:
float real;
float imaginary;
public:
Complex();
Complex(float real=0, float im=0);
float GetReal() const;
float GetImaginary() const;
Complex Add(const Complex &rhs) const;
Complex Subtract(const Complex &rhs) const;
Complex Multiply(const Complex &rhs) const;
void SetReal(float r);
void SetImaginary(float i);
};
Complex::Complex()
{
real=imaginary=0;
}
Complex::Complex(float realpart, float imaginarypart)
{
SetReal(real);
SetImaginary(imaginarypart);
}
void Complex::SetReal(float r)
{
real = r;
}
void Complex::SetImaginary(float i)
{
imaginary = i;
}
float Complex::GetReal() const
{
return real;
}
float Complex::GetImaginary() const {
return imaginary;
}
Complex Complex::Add(const Complex &rhs) const {
return Complex(GetReal() + rhs.GetReal(), GetImaginary() + rhs.GetImaginary());
}
Complex operator+(const Complex &rhs1, const Complex &rhs2) {
return rhs1.Add(rhs2);
}
Complex Complex::Subtract(const Complex &rhs) const
{
return Complex(GetReal() - rhs.GetReal(), GetImaginary() - rhs.GetImaginary());
}
Complex operator-(const Complex &rhs1, const Complex &rhs2)
{
return rhs1.Subtract(rhs2);
}
Complex Complex::Multiply(const Complex &rhs) const
{
return Complex(GetReal() * rhs.GetReal(), GetImaginary() * rhs.GetImaginary());
}
Complex operator*(const Complex &rhs1, const Complex &rhs2)
{
return rhs1.Multiply(rhs2);
}
int main()
{
Complex c();
Complex x(-2,4);
Complex y(5,6);
Complex z = x + y;
cout << z.GetReal() << '+' << z.GetImaginary() << 'i' << endl;
Complex e = x - y;
cout << e.GetReal() << '+' << e.GetImaginary() << 'i' << endl;
Complex r = x * y;
cout << r.GetReal() << '*' << r.GetImaginary() << 'i' << endl;
return 0;
}
but i take these output
8.99944e-039+10i
8.99944e-039+-2i
8.99944e-039*24i
Can somebody help me for this error ?
3 issues in your code:
Complex::Complex(float realpart, float imaginarypart)
{
SetReal(realpart);
SetImaginary(imaginarypart);
}
causes the warning:
<source>:24:28: warning: unused parameter 'realpart' [-Wunused-parameter]
24 | Complex::Complex(float realpart, float imaginarypart)
|
Fix it by passing realpart to SetReal or rather use the member initializer list:
Complex::Complex(float realpart, float imaginarypart) : real(realpart),imaginary(imaginarypart)
{}
Next, this:
Complex c();
is the most vexing parse. It declares a function named c taking no parameters and retuning a Complex. It is not declaring a variable c of type Complex. Write
Complex c;
Complex c{};
to call the default constructor. However, you class has two default constructors:
Complex();
Complex(float real=0, float im=0);
A default constructor is one that can be called without parameters and thats the case for both of these. Hence you currently cannot default construct a Complex, the constructors are ambigoous. I read your assignemnt as requiring you to provide two constructors:
Complex();
Complex(float real, float im); // no defaults !!
Then you will be able to default construct a Complex via Complex c; or Complex c{}; (but not via Complex c(); because thats a function declaration).
After fixing those, I get almost reasonable looking output: https://godbolt.org/z/x4xG8xzTf
Finally, your formula for multipliying two complex numbers is wrong. I'll leave that for you to fix it.

Why does this C++ snippet assigning a value to an rvalue compile?

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.

Rational class and Move Semantics not working

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

Operator overloading for add and compare data of Integer and Fraction classes

Similar to this problem posted here. I Need to create three classes:
"Number" class supports three operations,such as, “display”, “==”,
and “+”;
"Integer class" that represented by integer;
"Fraction" class is represented by numerator and denominator.
Requirements:
It should support the operations: (a) Integer (I) + Fraction (F),
(b) F+I, (c) F+F, (d) I+I, and comparing them
The caller of the + operation doesn't need to know the return type.
I could solve the problem till requirement# 1. However, couldn't figure out the second requirement yet. Any help would be appreciated.
To keep it brief, I am going to share the header file of my code below, function definition of the code can be shared if needed.
Number.h
#pragma once
template<class T>
class Number
{
public:
bool operator== (const T&)
{
return impl().operator == ();
}
T operator+ (const T &) const
{
return impl().operator+();
}
template <typename Stream>
void display(Stream& os) const
{
impl().display(os);
}
private:
T& impl() {
return *static_cast<T*>(this);
}
T const & impl() const {
return *static_cast<T const *>(this);
}
};
Integer.h
#pragma once
#include "Number.h"
class Integer : public Number<Integer>
{
int intValue{0};
public:
template <typename Stream>
void display(Stream& os) const
{
os << this->intValue << '\n';
}
Integer() = default;
~Integer() = default;
Integer(int num);
int getIntValue() const;
bool operator== (const Integer &);
Integer operator+ (const Integer &) const;
};
Fraction.h
#pragma once
#include <math.h>
#include "Number.h"
#include "Integer.h"
#include <iostream>
class Fraction : public Number<Fraction>
{
int _numerator{0};
int _denominator{1};
int gcdCalculate(int val1, int val2) const;
int lcmCalculate(const int val1, const int val2) const;
public:
template <typename Stream>
void display(Stream& os) const
{int tempNum = this->_numerator;
int tempDen = this->_denominator;
double tempFrac = (double)tempNum/(double)tempDen;
double intpart;
if (this->_denominator==0)
{
std::cout << "Undefined " << this->_numerator << "/" << this->_denominator << "(Divide by zero exception)";
}
else if (this->_denominator==1){
std::cout << this->_numerator << std::endl;
}
else {
os << this->_numerator << "/";
os << this->_denominator << '\n';}
}
Fraction() = default;
Fraction(int num, int den);
~Fraction() = default;
bool operator== (const Fraction &);
bool operator== (const Integer &);
friend bool operator== (const Integer&, const Fraction&);
Fraction operator+ (const Fraction &) const;
Fraction operator+ (const Integer &) const;
friend Fraction operator+ (const Integer&, const Fraction&);
};
main.cpp
#include <iostream>
using namespace std;
template <typename INumberType>
void GenericDisplay(const Number<INumberType>& num) //Here we are calling through the Number<> Interface
{
num.display(cout);
}
int main()
{
Fraction fracOne(1,4);
Fraction fracTwo(2,8);
Integer intOne(30);
Integer intTwo(30);
Fraction sumOfFractionOneTwo = fracOne + fracTwo;
Integer sumOfIntegerOneTwo = intOne + intTwo;
Fraction sumOfFractionOneAndIntegerOne = integerOne + fracOne;
Fraction sumOfFractionTwoAndIntegerTwo = fracTwo + intTwo;
return 0;
}
In this code, caller of the + operator knows the return type, e.g., in the int main() caller defined returned type "Fraction sumOfFractionOneAndIntegerOne = integerOne + fracOne;". Which is incorrect!
The way I want, caller should not know the return type. e.g., "Number sumOfFractionOneAndIntegerOne = integerOne + fracOne;"
Again, any help would be appreciated.
Since the type is statically known, the caller can use auto for the type of the variable, so that the type is deduced instead of explicitly specified. Otherwise, you may be looking for virtual inheritance, which allows an abstract base to be used as the type while derived classes provide implementation for further operators.

Operator Overloading: How to add and compare data of two class "Integer" and "Fraction"

I have two classes Integer and Fraction and one abstract class Number. I am suppose to perform addtion operation by overloading + and also I need to check equality of values using overloading of == operator on these classes.
Operations to be performed
1. Add Integer + Integer = Integer
2. Add Fraction + Fraction = Fraction
3. Add Integer + Fraction = Fraction
I have been able to do 1st and 2nd operation but not able to do addition of integer and fraction.
Below is the code snippet:
Number.h
#pragma once
#include <iostream>
template<class T>
class Number
{
virtual const T operator+ (const T &) = 0;
virtual void display(std::ostream &) const = 0;
virtual bool operator==(const T& rhs) const = 0;
};
Integer.h
#pragma once
#include "Number.h"
#include "Fraction.h"
class Integer : public Number<Integer>
{
int intValue;
public:
void display(std::ostream &) const;
int getValue() const;
void setValue(int);
Integer() {}
Integer(int num);
const Integer operator+ (const Integer &);
virtual ~Integer() {}
bool operator==(const Integer&) const;
};
Integer.cpp
#include "Integer.h"
#include "Number.h"
#include <iostream>
#include <string>
// parameterized constructor
Integer::Integer(int num)
{
intValue = num;
}
// return integer value
int Integer::getValue() const
{
return this->intValue;
}
void Integer::setValue(int x)
{
this->intValue = x;
}
// operator "+" overloading
const Integer Integer::operator+(const Integer &secondNumber)
{
Integer temp = this->intValue + secondNumber.intValue;
return temp;
}
// operator "=" overloading
void Integer::display(std::ostream& stream) const
{
stream << this->intValue;
}
// comparasion operator overload
bool Integer::operator==(const Integer& rhs) const
{
return this->intValue == rhs.intValue;
}
Fraction.h
#pragma once
#include "Number.h"
#include "Integer.h"
class Fraction : public Number<Fraction>
{
Integer _numerator;
Integer _denominator;
public:
void display(std::ostream &) const;
Fraction() = delete;
Fraction(const int &, const int &);
const Fraction operator+ (const Fraction &);
int gcdCalculate(int val1, int val2);
int lcmCalculate(const int val1, const int val2);
virtual ~Fraction() {}
bool operator==(const Fraction& rhs) const;
};
Fraction.cpp
#include "Fraction.h"
#include <iostream>
// parameterised constructor
Fraction::Fraction(const int & num, const int & den)
{
_numerator.setValue(num);
_denominator.setValue(den);
}
// display the fraction value
void Fraction::display(std::ostream & stream) const
{
if (this->_denominator == 0)
std::cout << "Undefined: " << this->_numerator.getValue() << "/" << this->_denominator.getValue() << " (Divide By Zero Exception)";
else
stream << this->_numerator.getValue() << "/" << this->_denominator.getValue();
}
// "+" operator overloading
const Fraction Fraction::operator+(const Fraction &numberTwo)
{
int lcm = lcmCalculate(this->_denominator.getValue(), numberTwo._denominator.getValue());
int multiplier1 = 0;
if (this->_denominator.getValue())
multiplier1 = lcm / this->_denominator.getValue();
int multiplier2 = 0;
if (numberTwo._denominator.getValue())
multiplier2 = lcm / numberTwo._denominator.getValue();
return Fraction((this->_numerator.getValue() * multiplier1) + (numberTwo._numerator.getValue() * multiplier2), lcm);
}
// LCM Calculation
int Fraction::lcmCalculate(const int val1, const int val2)
{
int temp = gcdCalculate(val1, val2);
return temp ? (val1 / temp * val2) : 0;
}
// GCD Calculation
int Fraction::gcdCalculate(int val1, int val2)
{
for (;;)
{
if (val1 == 0) return val2;
val2 %= val1;
if (val2 == 0) return val1;
val1 %= val2;
}
}
// comparision operator overload
bool Fraction::operator==(const Fraction& rhs) const
{
Integer numCheck = this->_numerator;
Integer denCheck = this->_denominator;
if (rhs._numerator.getValue())
numCheck.setValue(numCheck.getValue() / rhs._numerator.getValue());
if (rhs._numerator.getValue())
denCheck.setValue(denCheck.getValue() / rhs._denominator.getValue());
if (numCheck == denCheck) {
return true;
}
return false;
}
QUESTION:
I am confused as how to add Integer + Fraction class.
Do I need to create another class which will inherit from Number class.
How to overload oprator+ present in Number Class.
Suppose I try to add Integer + Fraction = Fraction in the Integer class itself then I will have something like
Example
class Integer : public Number<Integer>
{
const Fraction operator+(const Fraction &);
}
const Fraction Integer::operator+(const Fraction &numberTwo)
{
^^ I will get error here
// Addition opeartion
}
Please help me.
For your first question, the solution is to not use member function overloads, but to create a non-member function overload, e.g.
Fraction operator+(Integer const& integer, Fraction const& fraction)
{
// Logic to add the integer and fraction here
// Perhaps something like...
Fraction f(integer.getValue(), 1); // Create fraction
return f + fraction;
}
The code above uses the Fraction::operator+ function to add the integer.
While you can add an Integer+Fraction operator to your current design like Joachim suggested, that's going to result in some code duplication or at least some unnecessary boilerplate.
I suggest an alternative design instead: Make Integer convertible to Fraction. After all, any integer can be represented by the Fraction type, right?
You can make Integer convertible in two ways: By adding a conversion function to Integer, or by adding a converting constructor to Fraction.
I recommend choosing the converting constructor approach, because Fraction already depends on Integer type and so the cast operator would result in a circular dependency, just like your member operator attempt. I'll leave the implementation as an exercise.
This design requires that the addition operator is implemented as a non-member overload:
Fraction operator+(Fraction const& left, Fraction const& right)
With the converting constructor, this function can handle any combination of (F + F), (F + I) and (I + F).