In this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
// Ex8_05.cpp
// Overloaded assignment operator working well
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class CMessage
{
private:
char* pmessage; // Pointer to object text string
public:
// Function to display a message
void ShowIt() const
{
cout << endl << pmessage;
}
//Function to reset a message to *
void Reset()
{
char* temp = pmessage;
while(*temp)
*(temp++) = '*';
}
// Overloaded assignment operator for CMessage objects
CMessage operator=(const CMessage& aMess)
{
if(this != &aMess) // Check addresses are not equal
{
// Release memory for 1st operand
delete[] pmessage;
pmessage = new char[strlen(aMess.pmessage) + 1];
// Copy 2nd operand string to 1st
strcpy_s(this->pmessage, strlen(aMess.pmessage)+1, aMess.pmessage);
}
// Return a reference to 1st operand
return *this;
}
// Constructor definition
CMessage(const char* text = "Default message")
{
pmessage = new char[strlen(text) + 1]; // Allocate space for text
strcpy_s(pmessage, strlen(text)+1, text); // Copy text to new memory
}
// Copy constructor definition
CMessage(const CMessage& aMess)
{
size_t len = strlen(aMess.pmessage)+1;
pmessage = new char[len];
strcpy_s(pmessage, len, aMess.pmessage);
}
// Destructor to free memory allocated by new
~CMessage()
{
cout << "Destructor called." // Just to track what happens
<< endl;
delete[] pmessage; // Free memory assigned to pointer
}
};
int main()
{
CMessage motto1("The devil takes care of his own");
CMessage motto2;
CMessage motto3;
cout << "motto2 contains - ";
motto2.ShowIt();
cout << endl;
(motto1 = motto2) = motto3;
cout << "motto2 contains - ";
motto2.ShowIt();
cout << endl;
motto1.Reset(); // Setting motto1 to * doesn't
// affect motto2
cout << "motto1 now contains - ";
motto1.ShowIt();
cout << endl;
cout << "motto2 still contains - ";
motto2.ShowIt();
cout << endl;
return 0;
}
|
One line 78 shouldn't there be a error since a rvalue is returned on the left side of the assignment operator? Atleast thats what my book says. I understand that this will point to the same object when you return it so it isn't a rvalue but why does my book say this then?
Book:
"You can fix this with your own assignment operator function, which I will assume is defined within the class definition. Here’s a first stab at it, which I’ll warn you now is not sufficient for proper operation:
1 2 3 4 5 6 7 8
|
// Overloaded assignment operator for CMessage objects CMessage& operator=(const CMessage& aMess)
{
// Release memory for 1st operand delete[] pmessage;
pmessage = new char[strlen(aMess.pmessage) + 1];
// Copy 2nd operand string to 1st
strcpy_s(this->pmessage, strlen(aMess.pmessage) + 1, aMess.pmessage);
return *this;
}
|
An assignment might seem very simple, but there’s a couple of subtleties that need further investigation. First of all, note that you return a reference from the assignment operator function. It may not be immediately apparent why this is so — after all, the function does complete the assignment operation entirely, and the object on the right of the assignment will be copied to that on the left. Superficially, this would suggest that you don’t need to return anything, but you need to consider in a little more depth how the operator might be used.
You might need to use the result of an assignment operation on the right-hand side of another assignment. Consider this statement:
motto1 = motto2 = motto3;
The assignment operator is right-associative so the assignment of motto3 to motto2 will be carried out first. The statement will translate into the following:
motto1 = (motto2.operator=(motto3));
The result of the operator function call is on the right of the equals sign, so the statement will finally become this:
motto1.operator=(motto2.operator=(motto3));
If this is to work, you certainly have to return something from the operator=() function. The function call between the parentheses must return an object that can be used as the argument to the other operator=() function call. In this case, a return type of either CMessage or CMessage& would do it, so a reference is not mandatory for this situation, but you must at least return a CMessage object.
However, consider the following example:
(motto1 = motto2) = motto3;
This is perfectly legitimate code — the parentheses serve to make sure the leftmost assignment is carried out first. This translates into the following statement:
(motto1.operator=(motto2)) = motto3;
When you express the remaining assignment operation as the explicit overloaded function call, this ultimately becomes:
(motto1.operator=(motto2)).operator=(motto3);
Now, you have a situation where the object returned from the operator=() function is used to call the operator=() function. If the return type is just CMessage, this will not be legal because a temporary copy of the original object is actually returned so it will be an rvalue, and the compiler will not allow a member function call using an rvalue. The only way to ensure this will compile and work correctly is to return a reference, which is an lvalue. The only possible return type if you want to allow fully flexible use of the assignment operator with your class objects is CMessage&."
Can anyone please help? Thanks :D or is it that my author is just really dumb?