#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    132
    Rep Power
    3

    Question about >> operator


    I have a question.

    Here's some implementation of operator overloading (I copied only relevant code segments):

    Fraction.h:
    Code:
    class Fraction
    {
    private:
    	long int m_Nom;
    	long int m_Denom;
    public:
    	Fraction(long int nom=0, long int denom=1);
    	friend istream& operator>>(istream &is, Fraction &frac);
    }
    
    Fraction.cpp:
    Fraction::Fraction(long int nom, long int denom)
    {
    	cout<<"Fraction Ctor called"<<endl;
    	m_Nom=nom;
    	m_Denom=denom;
    	if (m_Denom==0)
    		m_Denom=1;
    	Reduce();
    	SetSign();
    }
    
    istream& operator>>(istream &is, Fraction &frac)
    {
    	char divSign;
    	is>>frac.m_Nom>>divSign>>frac.m_Denom;
    	if (frac.m_Denom==0)
    		frac.m_Denom=1;
    	frac.Reduce();
    	return is;
    }
    
    
    Monom.cpp:
    class Monom
    {
    private:
    	Fraction coefficient;
    	long int exponent;
    public:
    	friend istream& operator>>(istream& is, Monom &mon);
    }
    
    Monom.h:
    istream& operator>>(istream& is, Monom &mon)
    {
    	char variable, expoSign;
    	return is>>mon.coefficient>>variable>>expoSign>>mon.exponent;
    }
    
    
    now, here's main():
    
    int main()
    {
    	Monom M;
    }
    (only a declaration)

    and the output is:
    Fraction Ctor called
    Fraction Ctor called

    why is the Fraction constructor called twice?!
    Last edited by so.very.tired; April 14th, 2013 at 08:15 AM.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2013
    Posts
    159
    Rep Power
    20
    What is contained in your Reduce() and SetSign() functions?

    Jim
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2012
    Posts
    85
    Rep Power
    39
    Can you post enough code, so that it compiles and produces the behaviour you're describing? I can't reproduce your output if I insert empty definitions for SetSign and Reduce (or if I remove the calls to them).

    Maybe the SetSign and/or Reduce methods do something that causes the constructor to be called a second time (like creating a temporary Fraction variable). Though it'd have to be so that they only do it some times, otherwise you'd get an infinite number of constructor calls.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    132
    Rep Power
    3
    OK, I'll post the whole code:

    Fraction.h:
    Code:
    class Fraction
    {
    private:
    	long int m_Nom;
    	long int m_Denom;
    	void Reduce();
    	void SetSign();
    public:
    	Fraction(long int nom=0, long int denom=1);
    	friend Fraction operator+(const Fraction &frac1, const Fraction &frac2);
    	friend Fraction operator*(const Fraction &frac1, const Fraction &frac2);
    	friend Fraction operator-(const Fraction &frac2, const Fraction &frac1);
    	friend ostream& operator<<(ostream &os, const Fraction &frac);
    	friend istream& operator>>(istream &is, Fraction &frac);
    	Fraction& operator++();
    	const Fraction operator++(int);
    	Fraction& operator=(const Fraction &frac);
    	bool operator==(const Fraction &frac1)const;
    };
    
    
    Fraction.cpp:
    
    int FindGCD(long int i, long int j)
    {
    	if ((i==0)||(j==0))
    		return i+j;
    	if (i<0) i*=-1;
    
    	while (j)
    	{
    		long int temp=i%j;
    		i=j;
    		j=temp;
    	}
    	return i;
    }
    
    
    void Fraction::Reduce()
    {
    	int g=FindGCD(m_Nom, m_Denom);
    	m_Nom/=g;
    	m_Denom/=g;
    }
    
    
    void Fraction::SetSign()
    {
    	if (m_Denom<0)
    	{
    		m_Nom*=-1;
    		m_Denom*=-1;
    	}
    }
    
    
    Fraction::Fraction(long int nom, long int denom)
    {
    	cout<<"Fraction Ctor called"<<endl;
    	m_Nom=nom;
    	m_Denom=denom;
    	if (m_Denom==0)
    		m_Denom=1;
    	Reduce();
    	SetSign();
    }
    
    
    ostream& operator<<(ostream &os, const Fraction &frac)
    {
    	if (frac.m_Denom==1)
    		return os<<frac.m_Nom;
    	else
    		return os<<frac.m_Nom<<"/"<<frac.m_Denom;
    }
    
    
    istream& operator>>(istream &is, Fraction &frac)
    {
    	char divSign;
    	is>>frac.m_Nom>>divSign>>frac.m_Denom;
    	if (frac.m_Denom==0)
    		frac.m_Denom=1;
    	frac.Reduce();
    	return is;
    }
    
    
    Fraction operator+(const Fraction &frac1, const Fraction &frac2)
    {
    	long int nom=frac1.m_Nom*frac2.m_Denom+frac1.m_Denom*frac2.m_Nom;
    	long int denom=frac1.m_Denom*frac2.m_Denom;
    	long int g=FindGCD(nom, denom);
    	nom/=g;
    	denom/=g;
    	return Fraction(nom,denom);
    }
    
    
    Fraction operator-(const Fraction &frac1, const Fraction &frac2)
    {
    	long int nom=frac1.m_Nom*frac2.m_Denom-frac1.m_Denom*frac2.m_Nom;
    	long int denom=frac1.m_Denom*frac2.m_Denom;
    	long int g=FindGCD(nom, denom);
    	nom/=g;
    	denom/=g;
    	return Fraction(nom,denom);
    }
    
    Fraction operator*(const Fraction &frac1, const Fraction &frac2)
    {
    	long int nom=frac1.m_Nom*frac2.m_Nom;
    	long int denom=frac1.m_Denom*frac2.m_Denom;
    	long int g=FindGCD(nom, denom);
    	nom/=g;
    	denom/=g;
    	return Fraction(nom,denom);
    }
    
    
    Fraction& Fraction::operator++()
    {
    	m_Nom+=m_Denom;
    	Reduce();
    	return *this;
    }
    
    const Fraction Fraction::operator++(int)
    {
    	long int nom=m_Nom;
    	long int denom=m_Denom;
    	m_Nom+=m_Denom;
    	Reduce();
    	return Fraction(nom, denom);
    }
    
    Fraction& Fraction::operator=(const Fraction &frac)
    {
    	m_Nom=frac.m_Nom;
    	m_Denom=frac.m_Denom;
    	return *this;
    }
    
    
    bool Fraction::operator==(const Fraction &frac)const
    {
    	return m_Nom*frac.m_Denom==m_Denom*frac.m_Nom;
    }
    
    
    Monom.h:
    #define VARIABLE 'x'
    
    class Monom
    {
    private:
    	Fraction coefficient;
    	long int exponent;
    public:
    	Monom();
    	Monom(const Fraction &coef, long int exp=0);
    	Monom operator+(const Monom &mon);
    	Monom operator*(const Monom &mon);
    	Monom operator-(const Monom &mon);
    	bool operator==(const Monom &mon)const;
    	friend ostream& operator<<(ostream& os, const Monom &mon);
    	friend istream& operator>>(istream& is, Monom &mon);
    };
    
    
    Monom.cpp:
    
    Monom::Monom()
    {
    	coefficient=0;
    	exponent=0;
    }
    
    
    Monom::Monom(const Fraction &coef, long int exp)
    {
    	cout<<"Monom Ctr called"<<endl;
    	coefficient=coef;
    	exponent=exp;
    }
    
    Monom Monom::operator+(const Monom &mon)
    {
    	//if the two operands has different exponents...
    	if (exponent!=mon.exponent)
    		return *this;
    	Fraction coef=coefficient+mon.coefficient;
    	return Monom(coef, exponent);
    }
    
    Monom Monom::operator-(const Monom &mon)
    {
    	//if the two operands has different exponents...
    	if (exponent!=mon.exponent)
    		return *this;
    	Fraction coef=coefficient-mon.coefficient;
    	return Monom(coef, exponent);
    }
    
    Monom Monom::operator*(const Monom &mon)
    {
    	Fraction coef=coefficient*mon.coefficient;
    	long int exp=exponent+mon.exponent;
    	return Monom(coef, exp);
    }
    
    
    ostream& operator<<(ostream& os, const Monom &mon)
    {
    	if (mon.coefficient==0)
    		os<<0;
    	else if (mon.exponent==0)
    		os<<mon.coefficient;
    	else if ((mon.exponent==1)&&(mon.coefficient==1))
    		os<<VARIABLE;
    	else if (!(mon.exponent==1)&&(mon.coefficient==1))
    		os<<VARIABLE<<'^'<<mon.exponent;
    	else if ((mon.exponent==1)&&!(mon.coefficient==1))
    		os<<mon.coefficient<<VARIABLE;
    	else
    		os<<mon.coefficient<<VARIABLE<<'^'<<mon.exponent;
    
    	return os;
    }
    
    
    bool Monom::operator==(const Monom &mon)const
    {
    	return coefficient==mon.coefficient&&exponent==mon.exponent;
    }
    
    istream& operator>>(istream& is, Monom &mon)
    {
    	char variable, expoSign;
    	return is>>mon.coefficient>>variable>>expoSign>>mon.exponent;
    
    }
    Hope it's not too much.
    Thanks for the help.
    Last edited by so.very.tired; April 14th, 2013 at 08:11 AM.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2013
    Posts
    159
    Rep Power
    20
    The reason is because of this function:
    Code:
    Monom::Monom()
    {
    	coefficient=0;
    	exponent=0;
    }
    The variable coefficient is a fraction. Since you didn't use the initialization list this constructor actually constructs two instances of the Fraction class. Once to initialize an empty Fraction then again when calling the operator= in the body.

    To prevent this unnecessary duplication use initialization lists:

    Code:
    Monom::Monom() : coefficient(0), exponent(0)
    {  // Empty body.
    }
    Jim

    Comments on this post

    • sepp2k1 agrees : Faster and more comprehensive than I was
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2012
    Posts
    85
    Rep Power
    39
    Code:
    coefficient=0;
    This line creates a temporary Fraction object, calling the constructor a second time (as Fraction(0)).
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    132
    Rep Power
    3
    Thanks!

IMN logo majestic logo threadwatch logo seochat tools logo