< Previous | Contents | Next >

Overloading the Assignment Operator

When both sides of an assignment statement are objects of the same class, the classassignment operator member function is called. Like a default copy constructor, a default assignment operator member function is supplied for you if you dont write one of your own. Also like the default copy constructor, the default assignment operator provides only member-wise duplication.

For simple classes, the default assignment operator is usually fine. However, when you have a class with a data member that points to a value on the heap, you should consider writing an overloaded assignment operator of your own. If you dont, youll end up with shallow copies of objects when you assign one object to another. To avoid this problem, I overloaded the assignment operator for Critter. First, inside the class definition, I write the declaration:

Critter& Critter::operator=(const Critter& c); //overloaded assignment

op

Next, outside the class definition, I write the member function definition:

Critter& Critter::operator=(const Critter& c) //overloaded assignment op def

{

cout << "Overloaded Assignment Operator called\n"; if (this != &c)

{

delete m_pName;

m_pName = new string(*(c.m_pName)); m_Age = c.m_Age;

}

return *this;

}

Notice that the member function returns a reference to a Critter object. For robust assignment operation, return a reference from the overloaded assignment operator member function.

314 Chapter 9 n Advanced Classes and Dynamic Memory: Game Lobby


In main(), I call a function that tests the overloaded assignment operator for this class.

testAssignmentOp();

The testAssignmentOp() creates two objects and assigns one to the other.

Critter crit1("crit1", 7);

Critter crit2("crit2", 9); crit1 = crit2;

The preceding assignment statement, crit1 = crit2;, calls the assignment operator member functionoperator=()for crit1. In the operator=() func- tion, c is a constant reference to crit2. The goal of the member function is to assign the values of all of the data members of crit2 to crit1 while making sure each Critter object has its own chunks of memory on the heap for any pointer data members.

After operator=() displays a message that the overloaded assignment operator has been called, it uses the this pointer. Whats the this pointer? Its a pointer that all non-static member functions automatically have, which points to the object that was used to call the function. In this case, this points to crit1, the object being assigned to.

The next line, if (this != &c), checks to see whether the address of crit1 is not equal to the address of crit2that is, it tests if the object isnt being assigned to itself. Because its not, the block associated with the if statement executes.

Inside the if block, delete m_pName; frees the memory on the heap that crit1s m_pName data member pointed to. The line m_pName = new string(*(c.m_pName)); allocates a new chunk of memory on the heap, gets a copy of the string pointed to by the m_pName data member of crit2, copies the string object to the new heap memory, and points the m_pName data member of crit1 to this memory. You should follow this logic for all data members that point to memory on the heap.

The last line in the block, m_Age = c.m_Age; simply copies the value of the crit2s m_Age to crit1s m_Age data member. You should follow this simple member- wise copying for all data members that are not pointers to memory on the heap.

Finally, the member function returns a copy of the new crit1 by returning

*this. You should do the same for any overloaded assignment operator member function you write.

Introducing the Game Lobby Program 315


Back in testAssignmentOp(), I prove that the assignment worked by calling crit1.Greet() and crit2.Greet(). crit1 displays the message I’m crit2 and I’m 9 years old. &m_pName: 73F2ED48003AF644 while crit2 displays the message I’m crit2 and I’m 9 years old. &m_pName: 73F2ED48003AF634. The first part of each message, I’m crit2 and I’m 9 years old., is the same and shows that the copying of values worked. The second part of each message is different and shows that each object points to different chunks of memory on the heap, which demon- strates that I avoided shallow copies and have truly independent objects after the assignment.

In the last test of the overloaded assignment operator, I demonstrate what happens when you assign an object to itself. Thats what I do next in the function with the following lines:

Critter crit3("crit", 11); crit3 = crit3;

The preceding assignment statement, crit3 = crit3;, calls the assignment operator member functionoperator=()for crit3. The if statement checks to see whether crit3 is being assigned to itself. Because it is, the member function simply returns a reference to the object through return *this. You should follow this logic in your own overloaded assignment operator because of potential problems that can arise from only one object being involved in an assignment.


Hin t

image

When you have a class with a data member that points to memory on the heap, you should consider overloading the assignment operator for the class.

image