As described in Chapter 2, in C++ you can overload a function name so that it applies to more than one function. Similarly, you can overload the assignment operator (the = sign) to have more than one meaning; you can specify what happens when it is applied to instances of a particular class. This is known as “operator overloading.” Chapter 8 explains operator overloading in greater detail.
To redefine the meaning of the assignment operator for a class, you write a member function with the name operator=. If your class defines such a function, the compiler calls it to whenever one object is assigned to another. The compiler interprets an assignment statement like this
yourstring = mystring;
as a function call that looks like this:
yourstring.operator=( mystring );
In fact, you can explicitly use the second syntax to perform assignments; however, you should use the first syntax because it is more readable.
The assignment operator for String can be written as follows:
// Class Assignment
#include <iostream.h>
#include <string.h>
class String
{
public:
String();
String( const char *s );
String( char c, int n );
void operator=( const String &other );
// etc...
};
// ----------- Assignment operator
void String::operator=( const String &other )
{
length = other.length;
delete buf;
buf = new char[length + 1];
strcpy( buf, other.buf );
}
The assignment operator takes a reference to an object as its parameter. (Note that a reference to a constant is used, indicating that the function doesn't modify the object.) To perform the assignment, the function first copies the length data member. Next, it deletes the receiving object's buf pointer, returning that block of memory to the free store (this is safe even for an uninitialized string, because deleting a 0 pointer has no effect). Then the function allocates a new buffer and copies the other buffer's contents into it. This is illustrated in Figure 5.2.
Here's a program that uses the new String class with its assignment operator:
main()
{
String myString( "here's my string" );
myString.display();
cout << '\n';
String yourString( "here's your string" );
yourString.display();
cout << '\n';
yourString = myString;
yourString.display();
cout << '\n';
}
This program prints the following messages.
here's my string
here's your string
here's my string
What if a programmer using the String class accidentally assigns an object to itself? For instance:
myString = myString; // Self-assignment
Few people would write such a statement, but self-assignment can take other forms. For instance:
String *stringPtr = &myString;
// Later...
myString = *stringPtr; // Inconspicuous self-assignment
What happens during such an assignment? The operator= defined above first deletes myString's buffer, and allocates a new buffer. Then it copies the contents of myString's newly allocated buffer into itself. This causes unpredictable behavior in your program.
In order for the operator= function to work safely in all cases, it must check against self-assignment. This requires the use of the this pointer.