Function Overloading picking wrong type

I have two classes:

Fraction and UnitsFraction : Fraction.

UnitsFraction only has a string units; member more than fraction.

The problem is the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
    UnitsFraction a(7,2,"meters"),b(7,2,"meters"),c(7,2,"meters"),d(7,2,"meters");
    a=a.mult(b);

    cout<<endl<<typeid(a).name()<<endl;
    cout<<a;

    cout<<endl<<typeid(c.mult(d)).name()<<endl;
    cout<<c.mult(d);

    return 0;
}


this outputs this:

1
2
3
4
13UnitsFraction
49/4 meters * meters
13UnitsFraction
49/4


Meaning the first cout works like it is supposed to but the second one calls the ostream function defined for Fraction instead of the one for UnitsFraction.

Any ideas on why this happens, especially because type_id returns the same type for both statements.
Last edited on
What is the signature of mult? (ie, does it return a UnitsFraction or a Fraction?

(At least post the declarations of both classes)
Fraction:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Fraction
{
    protected:
        int num,den;

    public:
        //Constructors:
        Fraction(){num=0;den=0;normalize();}
        Fraction(const int &n, const int &d){set(n,d);}
        Fraction(const int &n){set(n,1);}

        //Copy-Constructor:
        Fraction(Fraction const &src){num=src.num;den=src.den;}

        void set(const int &n, const int &d){num=n;den=d;normalize();}  //Inline, because it's declared inside the class declaration
        int get_n() const {return num;}//const here makes sure that no changes are made to data members
        int get_d() const {return den;}//or functions that do so are called.

        //Operations:
        Fraction add(const Fraction &other); //Pass by reference is faster, as no copies are made
        Fraction sub(Fraction other);
        Fraction mult(const Fraction &other);
        Fraction div(const Fraction &other);

        //Operator Overloading:
        Fraction operator+(const Fraction &other){return add(other);}
        Fraction operator-(const Fraction &other){return sub(other);}
        Fraction operator*(const Fraction &other){return mult(other);}
        Fraction operator/(const Fraction &other){return div(other);}

        bool operator==(const Fraction &other){return (num==other.num && den==other.den);} //this expression evaluates to 1 if both are true or 0 if one or both are not.
        bool operator>(const Fraction &other){return (num*other.den>den*other.num);}
        bool operator<(const Fraction &other){return !(*this>other);}

        //Supporting other operand types with friend functions
        //Friend Functions are not member functions but can
        //access data members:
        friend Fraction operator+(const int &n, const Fraction &f1);
        friend Fraction operator-(const int &n, const Fraction &f1);
        friend Fraction operator*(const int &n, const Fraction &f1);
        friend Fraction operator/(const int &n, const Fraction &f1);
        friend ostream &operator<<(ostream &os, const Fraction &f1);
        friend bool operator==(const int &n, const Fraction &f1);
        friend bool operator>(const int &n, const Fraction &f1);
        friend bool operator<(const int &n, const Fraction &f1);



    private:
        void normalize();
        int gcf(const int &a, const int &b);
        int lcm(const int &a, const int &b);
};


UnitsFraction:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class UnitsFraction : public Fraction
{
    private:
    string units;

    public:
    //Ctrs:
    UnitsFraction(){set(0,1);}
    UnitsFraction(const int &n){set(n,1);}
    UnitsFraction(const int &n, const int &d){set(n,d);}
    UnitsFraction(const int &n, const int &d, const string &str){set(n,d);units=str;}

    //Cpy Ctrs:
    UnitsFraction(const UnitsFraction &src){num=src.num;den=src.den;units=src.units;}
        //Conversion Ctrs:
            UnitsFraction(const Fraction &src){set(src.get_n(),src.get_d());}

    //Overriden Methods:
    UnitsFraction add(const UnitsFraction &other);
    UnitsFraction operator+(const UnitsFraction &other){return add(other);}
    int operator==(const UnitsFraction &other){return (num==other.num && den==other.den && units==other.units);}
    UnitsFraction mult(const UnitsFraction &other);
    UnitsFraction operator*(const UnitsFraction &other){return this->mult(other);}

    friend ostream &operator<<(ostream &os, UnitsFraction &Un);

};


Fraction Mult:
1
2
3
4
5
6
7
8
Fraction Fraction::mult(const Fraction &other)
{
    Fraction result;

    result.set(num*other.num,other.den*den);

    return result;
}


UnitsFraction mult:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
UnitsFraction UnitsFraction::mult(const UnitsFraction &other)
{
    UnitsFraction result=Fraction::mult(other);

    if(this->units.size()==0)
        result.units=other.units;

    else if(other.units.size()==0)
        result.units=this->units;

    else
        result.units=this->units+" * "+other.units;

    return result;

}


I don't understand how can type_id return the same object type, but then different ostream functions are ran..
Ok... I'm not sure why you are seeing what you are seeing (what compiler are you using?), however I can say that you have some serious design problems.

None of the methods in UnitFraction actually overload the methods of Fraction; instead, they hide them. This is because of two things: one, none of the methods are declared virtual in the base class, and two, even if you did declare them virtual, the method signatures differ anyway.



I'm following "C++ Without Fear", this is the chapter on Inheritance, polymorphism comes after this one and I believe there's where virtual functions are discussed.

I don't really know what virtual functions are yet. I'm using C::B the one that ships with the compiler built-in.

"The codeblocks-10.05mingw-setup.exe file includes the GCC compiler and GDB debugger from MinGW."

Would you recommend any other?
I've now learned about virtual functions and changed the implementation for printing Fraction and subclasses.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Fraction
{
    protected:
        int num,den;
        virtual void normalize();
        virtual void print_this(ostream &os);
....
no changes
....
};

void Fraction::print_this(ostream &os)
{
    os<<num<<"/"<<den;
}

ostream &operator<<(ostream &os, Fraction &f1)
{
    f1.print_this(os);
    return os;
}


UnitsFraction : public Fraction, now only overloads print_this() and not the ostream operator.

class UnitsFraction : public Fraction
{
private:
string units;

public:

...

void print_this(ostream &os){os<<"Hello";}

};

I let alone main.cpp, now it doesn't compile and spits this out:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
o\Cpp\cpp_without_fear\float_fract\main.cpp||In function 'int main()':|
o\Cpp\cpp_without_fear\float_fract\main.cpp|102|error: no match for 'operator<<' in 'std::cout << UnitsFraction::add(const UnitsFraction&)(((const UnitsFraction&)((const UnitsFraction*)(& d))))'|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|108|note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|117|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|127|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|165|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|169|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|173|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\ostream.tcc|91|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|180|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\ostream.tcc|105|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|191|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|200|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|204|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|209|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|213|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|221|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ostream|225|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\ostream.tcc|119|note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]|
o\Cpp\cpp_without_fear\float_fract\fraction.h|52|note:                 std::ostream& operator<<(std::ostream&, Fraction&)|
||=== Build finished: 1 errors, 0 warnings ===|


If I remove this cout<<c.mult(d); it compiles and outputs "hello" as expected..
Your operator<< functions should take Fraction and UnitsFraction by const reference (you are passing by [non-const] reference).
Yes it works, thanks.

I still can't understand why would the first cout statement work fine but not the second. If you can explain me why or point me to something that would, I'd appreciate.

Thank's in advace,

Hugo Ribeira
Oh, I looked at your code again and now I know why. It's the same problem that you just fixed.

You had:

1
2
ostream& operator<<( ostream&, const Fraction& );  /* const reference */
ostream& operator<<( ostream&, UnitsFraction& );   /* non-const reference */


Your mult() function in UnitsFraction returns a UnitsFraction by value. Thus the expression a.mult(b) returns a temporary. The standard does not permit binding temporaries to non-const references, so the compiler could not call the the second operator<<. But it could upcast the temporary to the base type (Fraction) and call that operator<< instead.

Thank's I'd never get that by myself. It actually scares me that you guys can..

Anyways, thank you very much, It's always better to know why something didn't work, then just to know how to fix it.
Topic archived. No new replies allowed.