Overloaded assignment operator

A

August1

Below are the declaration for an overloaded assignment operator in an
interface file in addition to the implementation file definition of
the function. What would be an appropriate if condition to ensure
that a client of the program cannot assign an object of the class to
itself. The if() condition would be placed within the function
definition to compare the operand in the function parameter is not the
same as the temporary object being created.


//MutualFund.h - interface file
//overloaded assignment operator declaration
MutualFund& operator = (const MutualFund&);

//MutualFund.cpp - implementation file
//definition
MutualFund& MutualFund::eek:perator = (const MutualFund& operand)
{
szFundName = new char[25];
strcpy(szFundName,operand.szFundName);
iFundShares = operand.iFundShares;
dShareValue = operand.dShareValue;
dPortfolioValue = operand.dPortfolioValue;
return *this;
}

//Fund.cpp - client file

MutualFund fund1;

/*Rather than declaring object of the class and assigning the values
of all data members to the object's data members as desired with a
foloowing statement,

MutualFund fund2;
fund2 = fund1;

the user does this,
fund1 = fund1;

this is why there should be a condition to test that an object is not
assigned to itself*/

Thanks,
Anthony
 
J

John Harrison

August1 said:
Below are the declaration for an overloaded assignment operator in an
interface file in addition to the implementation file definition of
the function. What would be an appropriate if condition to ensure
that a client of the program cannot assign an object of the class to
itself. The if() condition would be placed within the function
definition to compare the operand in the function parameter is not the
same as the temporary object being created.

Actually modern practise usually advises a different approach. You can
implement the assignment operator in terms of the copy constructor and a
swap method, so called copy and swap.

MutualFund& MutualFund::eek:perator = (const MutualFund& operand)
{
MutualFund tmp(operand);
swap(tmp);
return *this;
}

void MutualFund::swap(MutualFund& operand)
{
std::swap(szFundName, operand.szFundName);
std::swap(iFundShares, operand.iFundShares);
std::swap(dShareValue, operand.dShareValue);
std::swap(dPortfolioValue, operand.dPortfolioValue);
}

where std::swap in the standard C++ function to swap two values. This method
is superior for general use because it reuses existing code.

But since you were asked to do it a different way, here's a hint. Use the
address of an object to identify it. If two objects have the same address
they are the same object, if they have different addresses they are
different objects. So write an expression that compares the address of the
object you are assigning to with the address of the object you are assigning
from.

john
 
C

Chris

Actually modern practise usually advises a different approach. You can
implement the assignment operator in terms of the copy constructor and a
swap method, so called copy and swap.

it does? could i get a source for this advise? maybe a website or a book?
I'm just curious. It seems to me that this would be slower--more function
calls and the overhead for them--and that it takes more code to use this
method. i dunno, maybe its just me.

-chris
 
J

John Harrison

Chris said:
it does? could i get a source for this advise? maybe a website or a book?
I'm just curious. It seems to me that this would be slower--more function
calls and the overhead for them--and that it takes more code to use this
method. i dunno, maybe its just me.

-chris

Well, for instance, here http://rafb.net/efnet_cpp/faq/concepts/copyctor/ or
here http://www.gotw.ca/gotw/059.htm.

Both these refer to the exception safety aspect of copy and swap but that
doesn't seem the main point to me. Obviously almost every class needs a copy
constructor, and a swap method is also often useful (and usually very easy
to write). To me the main point of copy and swap is that once you have those
useful methods you can easily write boiler plate code for the assignment
operator, it's a no-brainer.

I'm not the slightest bit concerned about the extra function calls involved.
I just don't think the few extra microseconds are an issue for 99.99% of
programs. I don't see why you think there is more code, especially when swap
is useful in it's own right. If you are going to write copy ctor, assignment
and swap then there is less code if you implement assignment in terms of
copy and swap.

The only drawback is that copy and swap forces you to reallocate memory in
the assigned to object, you cannot reuse the memory that is already
allocated in the assigned to object. But that is the price you pay for
exception safety.

john
 
A

August1

But since you were asked to do it a different way, here's a hint. Use the
address of an object to identify it. If two objects have the same address
they are the same object, if they have different addresses they are
different objects. So write an expression that compares the address of the
object you are assigning to with the address of the object you are assigning
from.

john

John Harrison's code eg. comes closer to anything else I thought we
may have had in mind. Is there anything improper with the definition
I have provided below? After previous testing, it seems to execute as
desired.

MutualFund& MutualFund::eek:perator = (const MutualFund& operand)
{
if(&(*this) == &operand)//client attempts to assign class object to
itself
{
cout << "Cannot assign the same object to itself." << endl;
return *this;
}
else
{
/*values are actually changed here rather than assigning the same
values of one class object's data members to another's in order to
demonstrate the false value of the if() condition, in other words, the
client did not attempt to assign a class object to itself in this
instance. Normally the values would not be changed and each of the
values of the data members pertaining to the original
class object would be assigned to the data members of the newly
instantiated
class object via the assignment statement*/

szFundName = new char[25];
strcpy(szFundName,"Coca-Cola");
iFundShares = 40;
dShareValue = 20;
dPortfolioValue = operand.dPortfolioValue;
return *this;
}//end if-else
}

Thanks in advance...
anthony
 
J

John Harrison

August1 said:
John Harrison's code eg. comes closer to anything else I thought we
may have had in mind. Is there anything improper with the definition
I have provided below? After previous testing, it seems to execute as
desired.

MutualFund& MutualFund::eek:perator = (const MutualFund& operand)
{
if(&(*this) == &operand)//client attempts to assign class object to
itself
{
cout << "Cannot assign the same object to itself." << endl;
return *this;
}
else
{

It's correct, but

if(this == &operand)//client attempts to assign class object to

is equivalent and slightly simpler.

john
 
A

Andrew Koenig

Below are the declaration for an overloaded assignment operator in an
interface file in addition to the implementation file definition of
the function. What would be an appropriate if condition to ensure
that a client of the program cannot assign an object of the class to
itself.

Why would you ever want to ensure that a program does not assign an object
of the class to itself? Doing so makes the class dramatically less useful
than it would be otherwise, and I don't see any compensating advantages.
Can you tell us what they might be?
 
C

Chris

John Harrison said:
Well, for instance, here http://rafb.net/efnet_cpp/faq/concepts/copyctor/
or here http://www.gotw.ca/gotw/059.htm.

Both these refer to the exception safety aspect of copy and swap but that
doesn't seem the main point to me. Obviously almost every class needs a
copy constructor, and a swap method is also often useful (and usually very
easy to write). To me the main point of copy and swap is that once you
have those useful methods you can easily write boiler plate code for the
assignment operator, it's a no-brainer.

I'm not the slightest bit concerned about the extra function calls
involved. I just don't think the few extra microseconds are an issue for
99.99% of programs. I don't see why you think there is more code,
especially when swap is useful in it's own right. If you are going to
write copy ctor, assignment and swap then there is less code if you
implement assignment in terms of copy and swap.

The only drawback is that copy and swap forces you to reallocate memory in
the assigned to object, you cannot reuse the memory that is already
allocated in the assigned to object. But that is the price you pay for
exception safety.

thanks for the links. i definatly see the case for exception safety. and a
few extra cycles of cpu can be worth the extra protection.

-Chris
 
A

August1

Why would you ever want to ensure that a program does not assign an object
of the class to itself? Doing so makes the class dramatically less useful
than it would be otherwise, and I don't see any compensating advantages.
Can you tell us what they might be?

The intent is not to make the class less useful, but simpler to
follow. I'm also not certain how it would be less useful. For
example, let's say there is a variable of int type called num. Would
someone execute a statement like the following?

num = num;

I'm not certain of a practical purpose it could serve. The same is for
that we have been discussing. An object of a class is made,

//class Auto
Auto parts;

Then someone uses a statement such as

parts = parts;

rather than assigning the values of all of the data members to another
object instantiated from the class, which is easier to follow and no
less useful, as follows

Auto items;

items = parts;
 
R

Risto Lankinen

It's correct, but

if(this == &operand)//client attempts to assign class object to

is equivalent and slightly simpler.

Simpler, yes, but not quite equivalent! If the class type of *this
has a user-defined unary operator&(), then that will be called
instead, rendering the comparison to deal with computed rather
than actual address of "this".

This is an important point, because if the address of "operand"
(obviously having the same type as *this) is a result of some
computation, then the comparison may not be meaningful unless
a similar computation is applied to the address of *this as well.

If I saw an &(*this) in an unknown code, I would leave it alone,
knowing that either it is there for a purpose, or the compiler will
get rid of the inefficiency for me anyway.

Cheers!

- Risto -
 

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,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top