assignment operator overload error??

S

Sean

Can someone help me see why the following "operator=" overloading
doesn't work under g++? and the error message is copied here. I see no
reason the compiler complain this. Thanks,

[bash]$ g++ copyconstructor1.cpp
#copyconstructor1.cpp: In function `int main()':
#copyconstructor1.cpp:86: no match for `sample& = sample' operator
#copyconstructor1.cpp:53: candidates are: sample sample::eek:perator=(sample&)

=========================================
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(sample &ob); // overload assignment
};

// Normal constructor.
sample::sample()
{
s = new char('\0'); // s points to a null string.
if(!s) {
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
}

// Copy constructor.
sample::sample(const sample &ob)
{
s = new char[strlen(ob.s)+1];
if(!s) {
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
strcpy(s, ob.s);
}

// Load a string.
void sample::set(char *str)
{
s = new char[strlen(str)+1];
if(!s) {
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
strcpy(s, str);
}


sample sample::eek:perator=(sample &ob)
{
/* If the target string is not large enough
then allocate a new string. */
if(strlen(ob.s) > strlen(s)) {
delete [] s;
s = new char[strlen(ob.s)+1];
if(!s) {
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
}
strcpy(s, ob.s);
return *this;
}

// Return an object of type sample.
sample input()
{
char instr[80];
sample str;

cout << "Enter a string: ";
cin >> instr;

str.set(instr);
return str;
}

int main()
{
sample ob;

ob = input(); // This doesn't compile under g++
ob.show();

return 0;
}
 
J

John Harrison

Sean said:
Can someone help me see why the following "operator=" overloading
doesn't work under g++? and the error message is copied here. I see no
reason the compiler complain this. Thanks,

A few errors, see comments below.
[bash]$ g++ copyconstructor1.cpp
#copyconstructor1.cpp: In function `int main()':
#copyconstructor1.cpp:86: no match for `sample& = sample' operator
#copyconstructor1.cpp:53: candidates are: sample sample::eek:perator=(sample&)

=========================================
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(sample &ob); // overload assignment

Should be

sample operator=(const sample &ob); // overload assignment

You program does not compile because you wrote the assignment operator
with a non-const reference instead of a const reference.

There is a rule in C++ that you cannot bind a temporary to a non-const
reference, so assignment operators and copy constructors (and most other
things) should be writen with const references if possible.
};

// Normal constructor.
sample::sample()
{
s = new char('\0'); // s points to a null string.

This is wrong. You cannot mixup allocations with new and new[], because
you must free new with delete and new[] with delete[].

This is correct

s = new char[1];
s[0] = '\0';

This is wrong, new does not return NULL if it fails, instead it throws
an exeption.
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
}

// Copy constructor.
sample::sample(const sample &ob)
{
s = new char[strlen(ob.s)+1];
if(!s) {

Again, new never returns NULL.
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
strcpy(s, ob.s);
}

// Load a string.
void sample::set(char *str)
{
s = new char[strlen(str)+1];
if(!s) {
cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
strcpy(s, str);
}

This function is ill conceived. It also leaks memory becaise the string
will already have some memory allocated which you don't free.

You should rewrite this as a constructor

sample::sample(const char* str)
{
s = new char[strlen(str)+1];
strcpy(s, str);
}
sample sample::eek:perator=(sample &ob)
{
/* If the target string is not large enough
then allocate a new string. */
if(strlen(ob.s) > strlen(s)) {
delete [] s;
s = new char[strlen(ob.s)+1];
if(!s) {
Again.

cout << "Allocation error\n";
exit(1); // exit program if out of memory
}
}
strcpy(s, ob.s);
return *this;
}

// Return an object of type sample.
sample input()
{
char instr[80];
sample str;

cout << "Enter a string: ";
cin >> instr;

str.set(instr);
return str;
}

Now if you rewrite sample::set as a constructor this function becomes
really easy

sample int()
{
char instr[80];
cout << "Enter a string: ";
cin >> instr;
return instr;
}

The compiler will create a sample object from the instr array using the
constructor I advised you to write above.
int main()
{
sample ob;

ob = input(); // This doesn't compile under g++
ob.show();

return 0;
}

Above all you need to learn about const.

john
 
D

David White

Sean said:
Can someone help me see why the following "operator=" overloading
doesn't work under g++? and the error message is copied here. I see no
reason the compiler complain this. Thanks,

[bash]$ g++ copyconstructor1.cpp
#copyconstructor1.cpp: In function `int main()':
#copyconstructor1.cpp:86: no match for `sample& = sample' operator
#copyconstructor1.cpp:53: candidates are: sample
sample::eek:perator=(sample&)

=========================================
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(sample &ob); // overload assignment

It's unusual for operator= to return a copy of itself, which you are doing,
but I doubt that that's your problem. It's more likely that the reference
argument is not const. Try making this your operator=:
sample &operator=(const sample &ob);
};
[snip]

int main()
{
sample ob;

ob = input(); // This doesn't compile under g++

The compiler probably doesn't like passing the temporary returned by input()
as a non-const reference to the assignment operator. I actually thought the
standard prohibited this, but neither VC++ 6.0 nor VS .NET 2003 is
complaining about it.
ob.show();

return 0;
}

DW
 
J

John Harrison

The compiler probably doesn't like passing the temporary returned by input()
as a non-const reference to the assignment operator. I actually thought the
standard prohibited this, but neither VC++ 6.0 nor VS .NET 2003 is
complaining about it.

The standard does prevent it. With those compilers you can get the
correct behaviour if you turn on 'disable language extensions', the /Za
options.

john
 
D

David White

John Harrison said:
The standard does prevent it. With those compilers you can get the
correct behaviour if you turn on 'disable language extensions', the /Za
options.

Well, that's ridiculous. You should have to _enable_ the extensions with a
switch, not disable. Thanks.

DW
 
J

John Harrison

David said:
Well, that's ridiculous. You should have to _enable_ the extensions with a
switch, not disable. Thanks.

DW

Backwards compatibility I think. VC++ 6 could not compile <windows.h>
without 'language extensions'. Don't know if that is still the case but
I wouldn't be surprised.

john
 
D

Dave

I am studying C++, currently learning to overload the assignment
operator. My text book (by D.S. Malik) teaches that the assignment
operator overload function returns a const reference, but it does not
explain why. In trying to understand this, I see that an address is
passed, and that address is not being changed, but I expect the
overloaded assignment function to change the data referenced by that
address. So I am confused how it can be const.

While goggling for an explaination, I found a recent post where you
helped someone who did not use a const reference in an assignment
overload prototype statement. Could you help me understand what "bind
a temporary to a non-const reference" means?

Dave

Should be

sample operator=(const sample &ob); // overload assignment

You program does not compile because you wrote the assignment operator
with a non-const reference instead of a const reference.

There is a rule in C++ that you cannot bind a temporary to a non-const
reference, so assignment operators and copy constructors (and most other
things) should be writen with const references if possible.
... snip
 
K

Kai-Uwe Bux

Dave said:
I am studying C++, currently learning to overload the assignment
operator. My text book (by D.S. Malik) teaches that the assignment
operator overload function returns a const reference, but it does not
explain why.

If the book really makes that claim, it cannot give a reason because the
claim is false:

struct IntWrapper {

int i;

IntWrapper ( int ii = 0 )
: i ( ii )
{}

IntWrapper & inc ( void ) {
++ i;
return ( *this );
}

IntWrapper & operator= ( IntWrapper const & other ) {
i = other.i;
return ( *this );
}

}; // IntWrapper;

#include <iostream>

int main ( void ) {
IntWrapper a ( 5 );
IntWrapper b ( 3 );
( b = a ).inc().inc();
std::cout << b.i << '\n';
}



It also fails for the assignment operator that is automatically provided by
the compiler:


struct IntWrapper {

int i;

IntWrapper ( int ii = 0 )
: i ( ii )
{}

IntWrapper & inc ( void ) {
++ i;
return ( *this );
}

}; // IntWrapper;

#include <iostream>

int main ( void ) {
IntWrapper a ( 5 );
IntWrapper b ( 3 );
( b = a ).inc().inc();
std::cout << b.i << '\n';
}

In trying to understand this, I see that an address is
passed, and that address is not being changed, but I expect the
overloaded assignment function to change the data referenced by that
address. So I am confused how it can be const.

While goggling for an explaination, I found a recent post where you
helped someone who did not use a const reference in an assignment
overload prototype statement. Could you help me understand what "bind
a temporary to a non-const reference" means?

You are confusing three different things:

a) non-constness of the return type.
(it's not necessary to make the return type const)

b) non-constness of the operator= method.
(it usually is necessary to make this method non-const.)

c) constness of the argument type.
(it is usually a good idea to have the argument be const.)

This quote discusses item (c) from above. Neither (a) nor (b) are at issue
here.


Best

Kai-Uwe Bux
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top