Overloading the "=" operator for Complex numbers

Discussion in 'C++' started by Pmb, May 29, 2004.

  1. Pmb

    Pmb Guest

    I've been working on creating a Complex class for my own learning purpose
    (learn through doing etc.). I'm once again puzzled about something. I can't
    figure out how to overload the assignment operator.

    Here's what I'm trying to do. I've defined class Complex as

    class Complex {
    friend ostream &operator<<( ostream &, Complex & );
    public:
    Complex( float = 0.0, float = 0.0 );
    Complex operator+( Complex & );
    Complex operator-( Complex & );
    Complex operator*( Complex & );
    Complex operator/( Complex & );
    Complex operator=( Complex & );
    Complex conjugate();
    float magnitude();
    private:
    float re;
    float im;
    };

    The constructor is

    Complex::Complex( float a, float b )
    : re( a ), im( b ) { }

    I have no idea how to write the overload function though. This doesn't work

    Complex Complex::eek:perator=( Complex &z )
    {
    re = z.re;
    im = z.im;

    return *this;
    }


    Help!!!! :)

    Thanks in advance!

    Pmb
     
    Pmb, May 29, 2004
    #1
    1. Advertising

  2. * "Pmb" <> schriebt:
    > I have no idea how to write the overload function though. This doesn't work
    >
    > Complex Complex::eek:perator=( Complex &z )
    > {
    > re = z.re;
    > im = z.im;
    >
    > return *this;
    > }
    >
    >
    > Help!!!! :)


    Should the "=" operation ever _change_ the value that is on the right
    hand side of '='?

    No?

    In that case, it should be 'const'.

    Should you ever be able to write e.g.


    a = b = Complex( 1, 2 );

    ?

    Yes?

    In that case, the return value should be a reference so that it can
    be modified (e.g., in turn invoking '=' on the result).

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, May 29, 2004
    #2
    1. Advertising

  3. Pmb

    Pmb Guest

    "Alf P. Steinbach" <> wrote in message
    news:...
    > * "Pmb" <> schriebt:
    > > I have no idea how to write the overload function though. This doesn't

    work
    > >
    > > Complex Complex::eek:perator=( Complex &z )
    > > {
    > > re = z.re;
    > > im = z.im;
    > >
    > > return *this;
    > > }
    > >
    > >
    > > Help!!!! :)

    >
    > Should the "=" operation ever _change_ the value that is on the right
    > hand side of '='?
    >
    > No?
    >
    > In that case, it should be 'const'.


    I'm not interested in worrying about const and program integrity at this
    point. This code will never be used. This particular program is simply for
    me to learn about writing overload functions for operators.


    >
    > Should you ever be able to write e.g.
    >
    >
    > a = b = Complex( 1, 2 );
    >
    > ?
    >
    > Yes?
    >
    > In that case, the return value should be a reference so that it can
    > be modified (e.g., in turn invoking '=' on the result).


    Do you mean something like

    Complex &operator=( Complex & );

    Complex &Complex::eek:perator=( Complex &z )
    {
    <??>
    return this;
    }

    I still don't see what to place in the body to do the work. Suppose

    class Complex {
    friend ostream &operator<<( ostream &, Complex & );
    public:
    Complex( float = 0.0, float = 0.0 );
    Complex operator+( Complex & );
    Complex operator-( Complex & );
    Complex operator*( Complex & );
    Complex operator/( Complex & );
    Complex &operator=( Complex & );
    Complex conjugate();
    float magnitude();
    private:
    float re;
    float im;
    };

    It would seem to me that the operator function would be

    Complex &Complex::eek:perator=( Complex &z )
    {
    re = z.re;
    im = z.im;

    return this;
    }

    But this doesn't work.

    Pmb
     
    Pmb, May 29, 2004
    #3
  4. * "Pmb" <> schriebt:
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:...
    > > * "Pmb" <> schriebt:
    > > > I have no idea how to write the overload function though. This doesn't

    > work
    > > >
    > > > Complex Complex::eek:perator=( Complex &z )
    > > > {
    > > > re = z.re;
    > > > im = z.im;
    > > >
    > > > return *this;
    > > > }
    > > >
    > > >
    > > > Help!!!! :)

    > >
    > > Should the "=" operation ever _change_ the value that is on the right
    > > hand side of '='?
    > >
    > > No?
    > >
    > > In that case, it should be 'const'.

    >
    > I'm not interested in worrying about const and program integrity at this
    > point. This code will never be used. This particular program is simply for
    > me to learn about writing overload functions for operators.


    You will not learn about overloading in C++ if you refuse to consider
    'const'.



    > >
    > > Should you ever be able to write e.g.
    > >
    > >
    > > a = b = Complex( 1, 2 );
    > >
    > > ?
    > >
    > > Yes?
    > >
    > > In that case, the return value should be a reference so that it can
    > > be modified (e.g., in turn invoking '=' on the result).

    >
    > Do you mean something like
    >
    > Complex &operator=( Complex & );
    >
    > Complex &Complex::eek:perator=( Complex &z )
    > {
    > <??>
    > return this;
    > }
    >
    > I still don't see what to place in the body to do the work. Suppose
    >
    > class Complex {
    > friend ostream &operator<<( ostream &, Complex & );
    > public:
    > Complex( float = 0.0, float = 0.0 );
    > Complex operator+( Complex & );
    > Complex operator-( Complex & );
    > Complex operator*( Complex & );
    > Complex operator/( Complex & );
    > Complex &operator=( Complex & );
    > Complex conjugate();
    > float magnitude();
    > private:
    > float re;
    > float im;
    > };
    >
    > It would seem to me that the operator function would be
    >
    > Complex &Complex::eek:perator=( Complex &z )
    > {
    > re = z.re;
    > im = z.im;
    >
    > return this;
    > }
    >
    > But this doesn't work.


    Say rather, it does not _compile_.

    First make it compile.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, May 29, 2004
    #4
  5. Pmb wrote in news: in comp.lang.c++:

    > I've been working on creating a Complex class for my own learning
    > purpose (learn through doing etc.). I'm once again puzzled about
    > something. I can't figure out how to overload the assignment operator.
    >


    You're not overloading anything here, you're *declaring* and
    then *defining* Complex::eek:perator = ( Complex & );

    > Here's what I'm trying to do. I've defined class Complex as
    >


    #include <ostream> /* always try to make your examples compile */

    > class Complex {
    > friend ostream &operator<<( ostream &, Complex & );


    friend std::eek:stream &operator<<( std::eek:stream &, Complex & );

    When I compiled your code the above was the only error I found.

    > public:
    > Complex( float = 0.0, float = 0.0 );
    > Complex operator+( Complex & );
    > Complex operator-( Complex & );
    > Complex operator*( Complex & );
    > Complex operator/( Complex & );


    All of the above *create* a new value, so its appropriate that
    they return by value.

    > Complex operator=( Complex & );


    The above dose *not* create a new value, but modifies the
    'this' object, logicaly it should return Complex &.

    Also it doesn't modify is argument, so you should prefer
    Complex const &. As well as being "const correct" this will
    allow you to later write code like:

    Complex a( 1, 2 ), b( 2, 3 );

    a = b.conjugate();

    or:

    a = a + b;

    As the tempraries returned by + and .conjugate() can't be passed
    to a function that takes a non-const reference.

    > Complex conjugate();
    > float magnitude();
    > private:
    > float re;
    > float im;
    > };
    >
    > The constructor is
    >
    > Complex::Complex( float a, float b )
    > : re( a ), im( b ) { }
    >
    > I have no idea how to write the overload function though. This doesn't
    > work
    >
    > Complex Complex::eek:perator=( Complex &z )
    > {
    > re = z.re;
    > im = z.im;
    >
    > return *this;
    > }
    >


    What doesn't work about it, with the 'ostream' issue above
    fixed it compiles fine for me. Are you sure the error your
    seeing isn't coming from elswhere ?


    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, May 29, 2004
    #5
  6. > >
    > > I'm not interested in worrying about const and program integrity at this
    > > point. This code will never be used. This particular program is simply

    for
    > > me to learn about writing overload functions for operators.

    >
    > You will not learn about overloading in C++ if you refuse to consider
    > 'const'.
    >


    It's worse than that. With certain compilers you will learn illegal C++. If
    you then switch to a compiler that enforces const correctness you will have
    to relearn C++ that you thought you already knew.

    Pmb, its not so hard

    Complex operator+( const Complex & ) const;
    Complex& operator=( const Complex & );

    john
     
    John Harrison, May 29, 2004
    #6
  7. Pmb

    Pmb Guest

    "Alf P. Steinbach" <> wrote in message
    news:...
    > * "Pmb" <> schriebt:
    > >
    > > "Alf P. Steinbach" <> wrote in message
    > > news:...
    > > > * "Pmb" <> schriebt:
    > > > > I have no idea how to write the overload function though. This

    doesn't
    > > work
    > > > >
    > > > > Complex Complex::eek:perator=( Complex &z )
    > > > > {
    > > > > re = z.re;
    > > > > im = z.im;
    > > > >
    > > > > return *this;
    > > > > }
    > > > >
    > > > >
    > > > > Help!!!! :)
    > > >
    > > > Should the "=" operation ever _change_ the value that is on the right
    > > > hand side of '='?
    > > >
    > > > No?
    > > >
    > > > In that case, it should be 'const'.

    > >
    > > I'm not interested in worrying about const and program integrity at this
    > > point. This code will never be used. This particular program is simply

    for
    > > me to learn about writing overload functions for operators.

    >
    > You will not learn about overloading in C++ if you refuse to consider
    > 'const'.


    I didn't say that I refuse to consider const

    pmb
     
    Pmb, May 29, 2004
    #7
  8. Pmb

    Pmb Guest

    "John Harrison" <> wrote in message
    news:...
    > > >
    > > > I'm not interested in worrying about const and program integrity at

    this
    > > > point. This code will never be used. This particular program is simply

    > for
    > > > me to learn about writing overload functions for operators.

    > >
    > > You will not learn about overloading in C++ if you refuse to consider
    > > 'const'.
    > >

    >
    > It's worse than that. With certain compilers you will learn illegal C++.

    If
    > you then switch to a compiler that enforces const correctness you will

    have
    > to relearn C++ that you thought you already knew.


    I think you both read something into what I said that wasn't there. I said
    *at this point*. When I learn a new language and try examples I make them as
    simple as possible and work my way up. After I got this to compile and got
    the logic correct, I was going to go back and place in the const.'s.

    >
    > Pmb, its not so hard
    >
    > Complex operator+( const Complex & ) const;
    > Complex& operator=( const Complex & );


    Still doesn't work. However I'm not sure where the error is.

    thanks

    Pmb
     
    Pmb, May 29, 2004
    #8
  9. Pmb

    Pmb Guest

    "Rob Williscroft" <> wrote

    > What doesn't work about it, with the 'ostream' issue above
    > fixed it compiles fine for me. Are you sure the error your
    > seeing isn't coming from elswhere ?


    There wasn't an "ostream" issue. I simply didn't post the entire code. I
    suppose I should have in retrospect. The following is the compile error I
    get from the program below

    -----------------
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    d:\temp\test\example.cpp:
    Error E2285 d:\temp\test\example.cpp 130: Could not find a match for
    'Complex::eek:perator =(Complex)' in function main()
    Error E2285 d:\temp\test\example.cpp 138: Could not find a match for
    'Complex::eek:perator =(Complex)' in function main()
    Error E2285 d:\temp\test\example.cpp 139: Could not find a match for
    'Complex::eek:perator =(Complex)' in function main()
    Error E2285 d:\temp\test\example.cpp 140: Could not find a match for
    'Complex::eek:perator =(Complex)' in function main()
    Error E2285 d:\temp\test\example.cpp 141: Could not find a match for
    'Complex::eek:perator =(Complex)' in function main()
    Error E2285 d:\temp\test\example.cpp 148: Could not find a match for
    'Complex::eek:perator =(Complex)' in function main()
    *** 6 errors in Compile ***

    Tool completed with exit code 1
    ------------------

    Line 130 is " uConj = u.conjugate();"
    Lines 138-141 are

    138 "sum = u + v;"
    139 "diff = u - v;"
    140 "prod = u*v;"
    141 "ratio = u/v;"


    What am I doing wrong this time?

    Thanks

    Pmb



    _____________________________________________
    #include <iostream.h>
    #include <math.h>

    class Complex {
    friend ostream &operator<<( ostream &, Complex & );
    public:
    Complex( float = 0.0, float = 0.0 );
    Complex operator+( Complex & );
    Complex operator-( Complex & );
    Complex operator*( Complex & );
    Complex operator/( Complex & );
    Complex operator=( Complex & );
    private:
    float re;
    float im;
    };

    ostream &operator<<( ostream &output, Complex &z )
    {
    float x = z.re, y = z.im;

    if ( y == 0 ) // z = a
    output << x;
    else if ( x == 0 && y > 0 ) // z = i b
    output << "i " << y;
    else if ( x == 0 && y < 0 ) // z = - i b
    output << "- i " << -y;
    else if ( x > 0 && y > 0 ) // z = a + i b
    output << x << " + i " << z.im;
    else if ( x > 0 && y < 0 ) // z = a - i b
    output << x << " - i " << -y;
    else if ( x < 0 && y < 0 ) // z = -a - i b
    output << x << " - i " << -y;
    else if ( x < 0 && y > 0 ) // z = -a + i b
    output << x << " + i " << y;

    return output;
    }

    Complex::Complex( float a, float b )
    : re( a ), im( b) { }

    Complex Complex::eek:perator+( Complex &z )
    {
    return Complex( re + z.re, im + z.im );
    }

    Complex Complex::eek:perator-( Complex &z )
    {
    return Complex( re - z.re, im - z.im );
    }

    Complex Complex::eek:perator*( Complex &z )
    {
    // z1 = x1 + i y1, z2 = x2 + i y2
    //
    // z1*z2 = ( x1 + i y1 )*( x2 + i y2 )
    // = ( x1*x2 + i x1*y2 + i x2*y1 - y1*y2
    // = ( x1*x2 - y1*y2 ) + i ( x1*y2 + x2*y1 )

    float x1 = re, y1 = im, x2 = z.re , y2 = z.im;

    return Complex( x1*x2 - y1*y2, x1*y2 + x2*y1 );
    }

    Complex Complex::eek:perator/( Complex &z )
    {
    // z1 = x1 + i y1, z2 = x2 + i y2
    //
    // z1 z1 z2* z1*z2 z1*z2
    // -- = -- -- = ------ = -------------
    // z2 z2 z2* |z2|^2 x1*x1 + y1*y1
    //
    // z1*z2 = ( x1*x2 - y1*y2 ) + i ( x1*y2 + x2*y1 )
    //
    // z1 x1*x2 - y1*y2 x1*y2 + x2*y1
    // -- = ----------------- + i -------------
    // z2 x1*x1 + y1*y1 x1*x1 + y1*y1
    //
    // a = x1*x2 - y1*y2, b = x1*y2 + x2*y1, c = x1*x1 + y1*y1
    //
    // z1 a b
    // -- = -- + i -- = x + i y
    // z2 c c
    //
    // x = a/c, y = b/c
    //
    float x1 = re, y1 = im, x2 = z.re , y2 = z.im;
    float a, b, c, x, y;

    a = x1*x2 - y1*y2;
    b = x1*y2 + x2*y1;
    c = x1*x1 + y1*y1;
    x = a/c;
    y = b/c;

    return Complex( x, y );
    }

    Complex Complex::eek:perator=( Complex &z )
    {
    re = z.re;
    im = z.im;

    return *this;
    }


    Complex Complex::conjugate()
    {
    return Complex( re, -im);
    }

    float Complex::magnitude()
    {
    return sqrt( re*re + im*im );
    }

    int main()
    {
    Complex u( 1, 5 ), v( 2, 2 ), w( 1, 1 );
    Complex uConj, sum, prod, diff, ratio;
    float r;

    uConj = u.conjugate();
    r = u.magnitude();

    cout << "\nu = " << u << endl;
    cout << "\nv = " << v << endl;
    cout << "\nu* = " << uConj << endl;
    cout << "\n|u| = " << r << endl;

    sum = u + v;
    diff = u - v;
    prod = u*v;
    ratio = u/v;

    cout << "\nu + v = " << sum << endl;
    cout << "\nu - v = " << diff << endl;
    cout << "\nu*v = " << prod << endl;
    cout << "\nu/v = " << ratio << endl;

    sum = u + v + w;
    cout << "\nu + v + w = " << sum << endl;

    return 0;
    }
    _____________________________________________
     
    Pmb, May 29, 2004
    #9
  10. "Pmb" <> wrote in message
    news:...
    >
    > "Rob Williscroft" <> wrote
    >
    > > What doesn't work about it, with the 'ostream' issue above
    > > fixed it compiles fine for me. Are you sure the error your
    > > seeing isn't coming from elswhere ?

    >
    > There wasn't an "ostream" issue. I simply didn't post the entire code. I
    > suppose I should have in retrospect. The following is the compile error I
    > get from the program below
    >
    > -----------------
    > Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    > d:\temp\test\example.cpp:
    > Error E2285 d:\temp\test\example.cpp 130: Could not find a match for
    > 'Complex::eek:perator =(Complex)' in function main()
    > Error E2285 d:\temp\test\example.cpp 138: Could not find a match for
    > 'Complex::eek:perator =(Complex)' in function main()
    > Error E2285 d:\temp\test\example.cpp 139: Could not find a match for
    > 'Complex::eek:perator =(Complex)' in function main()
    > Error E2285 d:\temp\test\example.cpp 140: Could not find a match for
    > 'Complex::eek:perator =(Complex)' in function main()
    > Error E2285 d:\temp\test\example.cpp 141: Could not find a match for
    > 'Complex::eek:perator =(Complex)' in function main()
    > Error E2285 d:\temp\test\example.cpp 148: Could not find a match for
    > 'Complex::eek:perator =(Complex)' in function main()
    > *** 6 errors in Compile ***
    >
    > Tool completed with exit code 1
    > ------------------
    >
    > Line 130 is " uConj = u.conjugate();"
    > Lines 138-141 are
    >
    > 138 "sum = u + v;"
    > 139 "diff = u - v;"
    > 140 "prod = u*v;"
    > 141 "ratio = u/v;"
    >
    >
    > What am I doing wrong this time?


    Forgetting const, put the const in and it will compile.

    Complex& operator=(const Complex & );

    What you are failing to realise is that you cannot bind a temporary to a
    non-const reference.

    sum = u + v;

    u + v returns a temporary, you have declared your operator= with a non-const
    reference. Therefore you cannot use u + v on the right hand side of a
    operator=.

    Just add const.

    john
     
    John Harrison, May 29, 2004
    #10
  11. Pmb

    Pmb Guest

    "John Harrison" <> wrote in message
    news:...
    >
    > "Pmb" <> wrote in message
    > news:...
    > >
    > > "Rob Williscroft" <> wrote
    > >
    > > > What doesn't work about it, with the 'ostream' issue above
    > > > fixed it compiles fine for me. Are you sure the error your
    > > > seeing isn't coming from elswhere ?

    > >
    > > There wasn't an "ostream" issue. I simply didn't post the entire code. I
    > > suppose I should have in retrospect. The following is the compile error

    I
    > > get from the program below
    > >
    > > -----------------
    > > Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    > > d:\temp\test\example.cpp:
    > > Error E2285 d:\temp\test\example.cpp 130: Could not find a match for
    > > 'Complex::eek:perator =(Complex)' in function main()
    > > Error E2285 d:\temp\test\example.cpp 138: Could not find a match for
    > > 'Complex::eek:perator =(Complex)' in function main()
    > > Error E2285 d:\temp\test\example.cpp 139: Could not find a match for
    > > 'Complex::eek:perator =(Complex)' in function main()
    > > Error E2285 d:\temp\test\example.cpp 140: Could not find a match for
    > > 'Complex::eek:perator =(Complex)' in function main()
    > > Error E2285 d:\temp\test\example.cpp 141: Could not find a match for
    > > 'Complex::eek:perator =(Complex)' in function main()
    > > Error E2285 d:\temp\test\example.cpp 148: Could not find a match for
    > > 'Complex::eek:perator =(Complex)' in function main()
    > > *** 6 errors in Compile ***
    > >
    > > Tool completed with exit code 1
    > > ------------------
    > >
    > > Line 130 is " uConj = u.conjugate();"
    > > Lines 138-141 are
    > >
    > > 138 "sum = u + v;"
    > > 139 "diff = u - v;"
    > > 140 "prod = u*v;"
    > > 141 "ratio = u/v;"
    > >
    > >
    > > What am I doing wrong this time?

    >
    > Forgetting const, put the const in and it will compile.
    >
    > Complex& operator=(const Complex & );
    >
    > What you are failing to realise is that you cannot bind a temporary to a
    > non-const reference.


    I see no reason for that to be true.
    >
    > sum = u + v;
    >
    > u + v returns a temporary, you have declared your operator= with a

    non-const
    > reference. Therefore you cannot use u + v on the right hand side of a
    > operator=.
    >
    > Just add const.


    I disagree. I simplified the code I'm working on to the bare bones. It now
    reads

    _______________________________________
    #include <iostream.h>

    class Complex {
    public:
    Complex( float = 0.0, float = 0.0 );
    Complex &operator=( Complex & );
    float getRe() { return re; };
    float getIm() { return im; };
    private:
    float re;
    float im;
    };

    Complex::Complex( float a, float b )
    : re( a ), im( b) { }

    Complex& Complex::eek:perator=( Complex &z )
    {
    re = z.re;
    im = z.im;

    return *this;
    }


    int main()
    {
    Complex z1( 1, 5 ), z2( 0, 0 );
    float x, y;

    x = z2.getRe();
    y = z2.getIm();

    cout << "Components before 'operator=' call: (x,y) = ("
    << x << "," << y << ")" << endl;

    z2 = z1;

    x = z2.getRe();
    y = z2.getIm();

    cout << "\nComponents after 'operator=' call: (x,y) = ("
    << x << "," << y << ")" << endl;

    return 0;
    }
    _______________________________________

    This program works just fine. The output is

    ------------
    Components before 'operator=' call: (x,y) = (0,0)

    Components after 'operator=' call: (x,y) = (1,5)
    ------------

    That is exactly what I want it to do. Had I wanted to use this code further
    then perhaps I'd used const's. Not while I'm in a learning mode. When
    learning one seeks to understand when something is required and when it is
    not required and how it affects the logic etc. Perhaps everyone disagrees
    with the way I chose to learn. But that is the way I choose to learn

    Pmb
     
    Pmb, May 29, 2004
    #11
  12. > >
    > > Forgetting const, put the const in and it will compile.
    > >
    > > Complex& operator=(const Complex & );
    > >
    > > What you are failing to realise is that you cannot bind a temporary to a
    > > non-const reference.

    >
    > I see no reason for that to be true.


    You might not see a reason, other people don't see the reason, its somewhat
    controversial, but its in the C++ standard in black and white. However some
    compilers do not enforce that rule.

    > >
    > > sum = u + v;
    > >
    > > u + v returns a temporary, you have declared your operator= with a

    > non-const
    > > reference. Therefore you cannot use u + v on the right hand side of a
    > > operator=.
    > >
    > > Just add const.

    >
    > I disagree. I simplified the code I'm working on to the bare bones. It

    now
    > reads


    Fine but you've changed the program to avoid the problem I described. You no
    longer have a temporary on the rhs of an assignment.

    >
    > _______________________________________
    > #include <iostream.h>
    >
    > class Complex {
    > public:
    > Complex( float = 0.0, float = 0.0 );
    > Complex &operator=( Complex & );
    > float getRe() { return re; };
    > float getIm() { return im; };
    > private:
    > float re;
    > float im;
    > };
    >
    > Complex::Complex( float a, float b )
    > : re( a ), im( b) { }
    >
    > Complex& Complex::eek:perator=( Complex &z )
    > {
    > re = z.re;
    > im = z.im;
    >
    > return *this;
    > }
    >
    >
    > int main()
    > {
    > Complex z1( 1, 5 ), z2( 0, 0 );
    > float x, y;
    >
    > x = z2.getRe();
    > y = z2.getIm();
    >
    > cout << "Components before 'operator=' call: (x,y) = ("
    > << x << "," << y << ")" << endl;
    >
    > z2 = z1;
    >
    > x = z2.getRe();
    > y = z2.getIm();
    >
    > cout << "\nComponents after 'operator=' call: (x,y) = ("
    > << x << "," << y << ")" << endl;
    >
    > return 0;
    > }
    > _______________________________________
    >
    > This program works just fine. The output is
    >
    > ------------
    > Components before 'operator=' call: (x,y) = (0,0)
    >
    > Components after 'operator=' call: (x,y) = (1,5)
    > ------------
    >
    > That is exactly what I want it to do. Had I wanted to use this code

    further
    > then perhaps I'd used const's. Not while I'm in a learning mode. When
    > learning one seeks to understand when something is required and when it is
    > not required and how it affects the logic etc. Perhaps everyone disagrees
    > with the way I chose to learn. But that is the way I choose to learn


    I was just answering the question you asked, 'What have I done wrong this
    time?' I pointed out a way (the only way) to make your program compile, you
    chose to write a different program instead.

    john
     
    John Harrison, May 29, 2004
    #12
  13. Pmb

    Pmb Guest

    "John Harrison" <> wrote in message
    news:...
    > > >
    > > > Forgetting const, put the const in and it will compile.
    > > >
    > > > Complex& operator=(const Complex & );
    > > >
    > > > What you are failing to realise is that you cannot bind a temporary to

    a
    > > > non-const reference.

    > >
    > > I see no reason for that to be true.

    >
    > You might not see a reason, other people don't see the reason, its

    somewhat
    > controversial, but its in the C++ standard in black and white. However

    some
    > compilers do not enforce that rule.
    >
    > > >
    > > > sum = u + v;
    > > >
    > > > u + v returns a temporary, you have declared your operator= with a

    > > non-const
    > > > reference. Therefore you cannot use u + v on the right hand side of a
    > > > operator=.
    > > >
    > > > Just add const.

    > >
    > > I disagree. I simplified the code I'm working on to the bare bones. It

    > now
    > > reads

    >
    > Fine but you've changed the program to avoid the problem I described. You

    no
    > longer have a temporary on the rhs of an assignment.
    >
    > >
    > > _______________________________________
    > > #include <iostream.h>
    > >
    > > class Complex {
    > > public:
    > > Complex( float = 0.0, float = 0.0 );
    > > Complex &operator=( Complex & );
    > > float getRe() { return re; };
    > > float getIm() { return im; };
    > > private:
    > > float re;
    > > float im;
    > > };
    > >
    > > Complex::Complex( float a, float b )
    > > : re( a ), im( b) { }
    > >
    > > Complex& Complex::eek:perator=( Complex &z )
    > > {
    > > re = z.re;
    > > im = z.im;
    > >
    > > return *this;
    > > }
    > >
    > >
    > > int main()
    > > {
    > > Complex z1( 1, 5 ), z2( 0, 0 );
    > > float x, y;
    > >
    > > x = z2.getRe();
    > > y = z2.getIm();
    > >
    > > cout << "Components before 'operator=' call: (x,y) = ("
    > > << x << "," << y << ")" << endl;
    > >
    > > z2 = z1;
    > >
    > > x = z2.getRe();
    > > y = z2.getIm();
    > >
    > > cout << "\nComponents after 'operator=' call: (x,y) = ("
    > > << x << "," << y << ")" << endl;
    > >
    > > return 0;
    > > }
    > > _______________________________________
    > >
    > > This program works just fine. The output is
    > >
    > > ------------
    > > Components before 'operator=' call: (x,y) = (0,0)
    > >
    > > Components after 'operator=' call: (x,y) = (1,5)
    > > ------------
    > >
    > > That is exactly what I want it to do. Had I wanted to use this code

    > further
    > > then perhaps I'd used const's. Not while I'm in a learning mode. When
    > > learning one seeks to understand when something is required and when it

    is
    > > not required and how it affects the logic etc. Perhaps everyone

    disagrees
    > > with the way I chose to learn. But that is the way I choose to learn

    >
    > I was just answering the question you asked, 'What have I done wrong this
    > time?' I pointed out a way (the only way) to make your program compile,

    you
    > chose to write a different program instead.


    I think I see what you're saying. This is why I left the const's out -
    learning purposes. If what you say is true (and I now see that perhaps it
    is) then I would have missed this point had I put them in solely for the
    purpose of good programming practice. Now I know that there are
    circumstances where leaving the const out causes compile errors.

    Thanks

    Pmb
     
    Pmb, May 29, 2004
    #13
  14. >
    > I think I see what you're saying. This is why I left the const's out -
    > learning purposes. If what you say is true (and I now see that perhaps it
    > is) then I would have missed this point had I put them in solely for the
    > purpose of good programming practice. Now I know that there are
    > circumstances where leaving the const out causes compile errors.
    >
    > Thanks
    >
    > Pmb
    >


    In C there's a notion which says that any legal program that uses const
    would also be a legal program if all the consts were removed. That has never
    been true in C++.

    john
     
    John Harrison, May 29, 2004
    #14
  15. Pmb

    Pmb Guest

    "John Harrison" <> wrote in message
    news:...
    > >
    > > I think I see what you're saying. This is why I left the const's out -
    > > learning purposes. If what you say is true (and I now see that perhaps

    it
    > > is) then I would have missed this point had I put them in solely for the
    > > purpose of good programming practice. Now I know that there are
    > > circumstances where leaving the const out causes compile errors.
    > >
    > > Thanks
    > >
    > > Pmb
    > >

    >
    > In C there's a notion which says that any legal program that uses const
    > would also be a legal program if all the consts were removed. That has

    never
    > been true in C++.


    What does the C++ standard say on this issue?

    Pmb
     
    Pmb, May 29, 2004
    #15
  16. Pmb

    Pmb Guest

    ----- Original Message -----
    From: "John Harrison" <>
    Newsgroups: comp.lang.c++
    Sent: Saturday, May 29, 2004 7:50 AM
    Subject: Re: Overloading the "=" operator for Complex numbers


    > >
    > > I think I see what you're saying. This is why I left the const's out -
    > > learning purposes. If what you say is true (and I now see that perhaps

    it
    > > is) then I would have missed this point had I put them in solely for the
    > > purpose of good programming practice. Now I know that there are
    > > circumstances where leaving the const out causes compile errors.
    > >
    > > Thanks
    > >
    > > Pmb
    > >

    >
    > In C there's a notion which says that any legal program that uses const
    > would also be a legal program if all the consts were removed. That has

    never
    > been true in C++.


    While I now understand that I *must* put const in I still don't understand
    *why* I must do that? You wrote

    > What you are failing to realise is that you cannot bind a temporary to a

    non-const reference.

    What does "bind a temporary" mean?

    > sum = u + v;
    >
    > u + v returns a temporary, ...


    Please clarify. What do you mean by "returns a temporary"? I assume that
    you're referring to the return value of

    Complex Complex::eek:perator+( Complex &z )

    Since this is a temporary and since this is what goes into the input of

    Complex& Complex::eek:perator=( const Complex &z )

    Then shouldn't the input be temporary?

    > ...you have declared your operator= with a non-const
    > reference.


    Doesn't "non-constant" mean "temporary"?

    Thanks

    Pmb

    ps - Sorry. I accidently sent this to your e-mail too
     
    Pmb, May 29, 2004
    #16
  17. Pmb

    JKop Guest

    Pmb posted:


    > While I now understand that I *must* put const in I still don't
    > understand *why* I must do that?



    int a = 6;
    const int b = 5;
    const int c = 4;


    a = b;


    Self explanatory I hope.


    >> What you are failing to realise is that you cannot bind a temporary to
    >> a non-const reference.

    >
    > What does "bind a temporary" mean?
    >
    >> sum = u + v;
    >>
    >> u + v returns a temporary, ...
    >>
    >> Please clarify. What do you mean by "returns a temporary"?


    unsigned int GiveNumber(void)
    {
    return 27;
    }

    int main(void)
    {
    int& given_number = GiveNumber();


    given_number = 27; //Guess what happens here...

    //The object returned from GiveNumber no longer exists, I have
    //a hanging pointer, in the form of a reference. And I just accessed
    //"unallocated" memory, memory that ain't mine. BOLD!
    }
     
    JKop, May 29, 2004
    #17
  18. Pmb

    Jeff Relf Guest

    Correct me if I'm wrong here C++ guys.

    Hi Pmb, ( and all you C++ guys too ) [ Posted & e-mailed ]

    You showed, " sum = u + v; ".

    And in your e-mail to me you showed:
    cin >> "Enter z = x + i y: " >> z;

    I'd be nice if one could say:
    cin >>
    "Enter z, ( in the form: Real + Imaginary ): " >> z;

    Then the user could simply type in something like:
    5 + 6

    But you can't overload the + symbol like that,
    because it reacts to the type of the operands,
    which, in this case, are not even reals,
    much less complex. ( They are integers )

    Could that be solved by
    using something other than the + symbol ?

    Correct me if I'm wrong here C++ guys,
    but I think the only solution is
    to use string input like this:

    float Real; String A_String_Operator; float Imaginary;
    cin >>
    "Enter z,"
    " ( in the form: Real + Imaginary, "
    " spaces required ): " >>
    Real >> A_String_Operator >> Imaginary;

    Then the user could simply type in something like:
    5 + 6
     
    Jeff Relf, May 29, 2004
    #18
  19. Pmb

    John Carson Guest

    "Pmb" <> wrote in message
    news:
    > ----- Original Message -----
    > From: "John Harrison" <>
    >
    > While I now understand that I *must* put const in I still don't
    > understand *why* I must do that? You wrote
    >
    >> What you are failing to realise is that you cannot bind a temporary
    >> to a non-const reference.

    >
    > What does "bind a temporary" mean?


    A reference refers to an object. A reference is "bound to a temporary" when
    it is made to refer to a temporary. The binding takes place in this instance
    when the temporary is passed as the operator argument.

    >> sum = u + v;
    >>
    >> u + v returns a temporary, ...

    >
    > Please clarify. What do you mean by "returns a temporary"? I assume
    > that you're referring to the return value of
    >
    > Complex Complex::eek:perator+( Complex &z )


    Correct.

    > Since this is a temporary and since this is what goes into the input
    > of
    >
    > Complex& Complex::eek:perator=( const Complex &z )
    >
    > Then shouldn't the input be temporary?


    Yes, the input is a temporary. But the reference is a const reference. You
    are allowed to bind temporaries to const references, but not to non-const
    references.

    > Doesn't "non-constant" mean "temporary"?


    No. const and non-const has to do with the right to modify an object. When
    you declare an operator with

    Complex& Complex::eek:perator=(Complex &z );

    the operator has the right to modify whatever is passed in as its argument.
    Thus the assignment in

    z = u;

    would allow u to be modified by the assignment operator. By contrast, a
    declaration of

    Complex& Complex::eek:perator=( const Complex &z );

    means that the assignment operator is not allowed to modify its argument (u
    in the above example).

    Why is only the second version allowed when the argument is a temporary?
    This is to prevent programmers from making a particular type of error. If a
    function or operator modifies its argument, then that usually means that the
    programmer wishes to change the object in the scope from which the function
    or operator has been called, as in the following example:

    void DoubleValue(int &n)
    {
    n *=2;
    }

    int main()
    {
    int m = 2;
    DoubleValue(m);
    // m will now be 4
    }

    Now if the argument passed to a function is a temporary, then the function's
    action will change the value of the temporary, but the temporary will cease
    to exist as soon as the function returns. Thus the function will not have an
    effect in the scope from which it is called. This may be an unpleasant
    surprise to the programmer, so the language prevents the passing of
    temporaries to functions and operators with non-const reference parameters
    in order to eliminate the possibility of this unpleasant surprise. The risk
    of this surprise is greater than you might think because temporaries get
    generated in more cases than you might think.


    --
    John Carson
    1. To reply to email address, remove donald
    2. Don't reply to email address (post here instead)
     
    John Carson, May 29, 2004
    #19
  20. "Pmb" <> wrote in message
    news:...
    >
    > ----- Original Message -----
    > From: "John Harrison" <>
    > Newsgroups: comp.lang.c++
    > Sent: Saturday, May 29, 2004 7:50 AM
    > Subject: Re: Overloading the "=" operator for Complex numbers
    >
    >
    > > >
    > > > I think I see what you're saying. This is why I left the const's out -
    > > > learning purposes. If what you say is true (and I now see that perhaps

    > it
    > > > is) then I would have missed this point had I put them in solely for

    the
    > > > purpose of good programming practice. Now I know that there are
    > > > circumstances where leaving the const out causes compile errors.
    > > >
    > > > Thanks
    > > >
    > > > Pmb
    > > >

    > >
    > > In C there's a notion which says that any legal program that uses const
    > > would also be a legal program if all the consts were removed. That has

    > never
    > > been true in C++.

    >
    > While I now understand that I *must* put const in I still don't understand
    > *why* I must do that? You wrote
    >
    > > What you are failing to realise is that you cannot bind a temporary to a

    > non-const reference.
    >
    > What does "bind a temporary" mean?
    >
    > > sum = u + v;
    > >
    > > u + v returns a temporary, ...

    >
    > Please clarify. What do you mean by "returns a temporary"? I assume that
    > you're referring to the return value of
    >
    > Complex Complex::eek:perator+( Complex &z )
    >
    > Since this is a temporary and since this is what goes into the input of
    >
    > Complex& Complex::eek:perator=( const Complex &z )
    >
    > Then shouldn't the input be temporary?
    >
    > > ...you have declared your operator= with a non-const
    > > reference.

    >
    > Doesn't "non-constant" mean "temporary"?
    >
    > Thanks
    >
    > Pmb
    >


    A temporary is an unnamed object. 'u + v' returns a Complex object, but that
    object has no name, so it's a temporary (the compiler creates it when the
    functions returns and destroys it when it been used, hence its called a
    temporary). Any function or operator that returns an object returns a
    temporary. There are various other ways to create temporaries

    class X
    {
    public:
    X(int x);
    };

    void f(const X& x);

    f(1);

    There's a constructor for X that takes an int, so when you try to call f
    using an int, the compiler creates a temporary X from the int and uses that
    to call f.

    You can also create temporaries explicitly

    Complex z = Complex(1.0, 2.0) + Complex(3.0, 4.0);

    The objects created by Complex(1.0, 2.0) and Complex(3.0, 4.0) have no name,
    they are temporaries.

    When a reference is initialised its usually referred to as binding a
    reference.

    int x;
    int& y = x; // y is bound to x

    Now the crunch, a temporary cannot be bound to a non-const reference.
    Suppose you have written

    class Complex
    {
    public:
    Complex operator+(Complex& rhs);

    Now this is illegal

    Complex z = Complex(1.0, 2.0) + Complex(3.0, 4.0);

    The right hand side of your operator+ is a temporary but you operator+ has
    been written with a non-const reference, so the above should not compile.
    Similarly

    Complex f();

    Complex z = Complex(1.0, 2.0) + f();

    Again the right hand side is a temporary.

    Why does C++ have this rule? That's a good question, Bjarne Stroustrup says
    that it leads to code that is too confusing, he has in mind code like this

    void trim_whitespace(string& s); // removes whitespace from s

    trim_whitespace(" abc ");

    Without the 'can't bind a temporary to a non-const reference' rule the
    compiler would create a temporary string from " abc ", that would be passed
    to trim_whitespace, which would faithfully remove the whitespace, but when
    the function returns the temporary (with its whitespace removed) would be
    destroyed. The original string literal " abc " would be completely
    untouched.

    With the rule the above will not compile, which it what you would want.

    As I said this isn't uncontroversial, but it is the way C++ is. If you want
    to consult the standard 8.5.3 para 5

    john
     
    John Harrison, May 29, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Smith
    Replies:
    2
    Views:
    425
    Ivan Vecerina
    Oct 6, 2004
  2. Arvid Requate
    Replies:
    2
    Views:
    992
    Alf P. Steinbach
    Jun 23, 2006
  3. john134
    Replies:
    7
    Views:
    391
    john134
    Jun 29, 2006
  4. Replies:
    11
    Views:
    737
    James Kanze
    May 16, 2007
  5. hurcan solter
    Replies:
    3
    Views:
    733
    Cholo Lennon
    Aug 29, 2007
Loading...

Share This Page