constructor / operator overload

Hi all,
I have this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Numbers {
    int A;
    int B;

    Numbers( int a = 0, int b = 0 ) {
        A = a;
        B = b;
    }

    void operator = ( Numbers& numbers ) {
        A = numbers.A;
        B = numbers.B;
    }
};

int main( int argc, char* argv[] ) {
    Numbers numbers;
    numbers = Numbers( 5, 10 );

    return 0;
}


In Visual Studio 11 it compiles fine, but in Code::Blocks and DevCpp it gives the error:
18 no match for 'operator=' in 'numbers = Numbers(5, 10)'
10 candidates are: void Numbers::operator=(Numbers&)


It seems that the compilers mingle the constructor and the operator. Does somebody have a solution?
Last edited on
Here are a few alternatives:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Option 1
Numbers* numbers;
numbers = new Numbers( 5, 10 );

// Option 2
Numbers numbers(5,10);

// Option 3
Numbers numbers = Numbers(5,10);

// Option 4
Numbers numbers;
Numbers temp = Numbers(5,10);
numbers = temp;


I'm surprised that it compiled in VS2011 for the following reason:
In line 17 numbers is created with the default constructor. By the time line 18 comes, the constructor has already been called. It can't be called again for the same object.

It thinks that this is the overload because numbers is an existing object and is being set to a new object created by the constructor Numbers(5,10).
Last edited on
Temporary objects can't bind to non-const references. The solution is to change the type of the operator= parameter to const Numbers&.
When you are using the MS VC++ you should switch off language extensions of MS VC++ in the project properties. Moreover MS VC++ has some bugs that deal with temporary objects. I wrote about this here http://cpp.forum24.ru/?1-3-0-00000045-000-0-0-1345837788

Though it is written in Russia but you can use for example google translate to translate the text in your native language.
Last edited on
Thanks both! It works now.

Temporary objects can't bind to non-const references.

Peter87, can you please explain that more detailed? Why cán they bind to const references?
Also you should correctly define the copy assignment operator. Instead of your definition

1
2
3
4
void operator = ( Numbers& numbers ) {
        A = numbers.A;
        B = numbers.B;
    }


shall be

1
2
3
4
5
6
Numbers & operator = ( const Numbers& numbers ) {
        A = numbers.A;
        B = numbers.B;

        return ( *this );
    }
@vlad from moscow: I know that return ( *this ) is useful because now you can chain statements. But what I don't get is the following:
Numbers & operator = ( const Numbers& numbers ) this means that the function returns a reference to an object of Numbers. A reference is just an address, right? And a pointer is an address too. And this is a pointer. So why not just return this ?
Last edited on
A reference is not the address of a variable - they happen to use the same character in their syntax (&), but they are completely different. When you do

 
Foo * pFoo = &someFoo;


you are saying "pFoo will point to the address of a Foo, and we are going to initialize it with the address of someFoo". A reference can be thought of as a way to provide just a new name for the same variable. In the case:

1
2
Foo someFoo;
Foo &refFoo = someFoo;


Notice you are initializing it to someFoo, not the address of someFoo. After this line, refFoo and someFoo can be used 100% interchangeably, and they both represent the exact same object internally - changes to 1 affect the other. This is slightly different from pointers, in that you can re-assign "pFoo" to another object, and it will not affect the original someFoo object (though you can affect the original someFoo object if you did something like pFoo->size = 10).

Onto the actual question... @Stewbond as well

as peter correctly stated, the code

1
2
Numbers numbers;                    //     [1]
numbers = Numbers( 5, 10 );    //     [2] 


actually calls 3 functions: at [1], the 'numbers' object is constructed using the default constructor fo Numbers. At [2], first a whole new object is created with "Numbers(5, 10)". This object is not bound to a variable; it is called a 'temporary' or 'rvalue', and because there is no variable associated with this newly created object, it goes out of scope as soon as the expression exits. The 3rd function being (attempting to be) called is operator=(Numbers &). You are trying to pass in this newly created rvalue object to operator=, but operator= expects a reference to a 'Numbers' object, which may be modified inside the operator= method (by nature of that method not taking a const parameter). But it doesn't make sense to allow editing of a Numbers object that is temporary, as by definition it isn't sticking around after the function exits. To fix your code in main, you can instead write:

1
2
3
Numbers numbers;
Numbers temp(5, 10);
numbers = temp;


Now your code will work, because operator= has something to bind the parameter to - the 'temp' variable. Alternately, you can (and should, as good practice) change operator= to take a const Numbers &, for 2 reasons: 1 is that since the value isn't actually being modified, it's the right thing to do, and 2 that a const reference can accept r-values or even construct entirely new objects as needed. A good example is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Foo1 (string & str)
{

}

void Foo2(const string & str)
{

}

...

Foo1("Hello"); // Won't compile - we want a string, not a const char *
Foo2("World"); // will compile - compiler is allowed to generate a temporary string object, and use the string::string(const char *) constructor to initialize 


As a final note: MSVC seems to allow binding of an rvalue to a non-const reference. This behavior doesn't seem 100% wrong to me, as the lifetime of the temporary extends until the end of the expression in which it is created, which will be after the function returns. It is however non-standard (I believe), and perhaps a somewhat 'bad practice'.
Last edited on
Wow, thanks a lot, rollie. That really cleared things up! :)
Topic archived. No new replies allowed.