Solving the Assignment Operator Problem

Although it's actually possible to get the effect of two independent strings without the extra work of allocating memory and copying data every time an assignment is done, the mechanisms needed to do that are beyond the scope of this book.[11] By far the easiest way to have the effect of two independent strings is to actually make another copy of a string's data whenever we copy the string, and that's how we'll do it here. The results will be as indicated in Figure 7.12.

[11] We'll see how to implement a similar feature in another context when we get back to the discussion of inventory control later.

Figure 7.12. strings n and s in memory after custom =


With this arrangement, a change to one of the string variables will leave the other one unaffected, as the user would expect. To make this happen, we have to implement our own operator =, which will copy the data rather than just the pointer to the data. That's the operator declared in Figure 7.1 by the line:

string& operator = (const string& Str);

What exactly does this mean? Well, as with all function declarations, the first part of the function declaration indicates the return type of the function. In this case, we're going to return a reference to the string to which we're assigning a value; that is, the string on the left of the = sign in an assignment statement. While this may seem reasonable at first glance, actually it's not at all obvious why we should return anything from operator =. After all, if we say a = b;, after a has been set to the same value as b, we're done; that operation is performed by the = operator, so no return value is needed after the assignment is completed.

However, there are two reasons why assignment of native types returns a value, which is equal to the value that was assigned to the left hand argument of =. First, it allows us to write an if statement such as if (a = b), when we really meant if (a == b); of course, this will cause a bug in the program, since these two statements don't have the same meaning. The first one sets a to b and returns the value of a; if a isn't 0, then the if condition is considered true. The latter statement, of course, compares a and b for equality and makes the if condition true if they are equal. To help prevent the error of substituting = for == in this situation, many compilers have a warning that indicates your use of, say, if (a = b); unfortunately, this is a legal construct with native types, and so cannot generate a compiler error. As it happens, using = in this way is an illegal operation with class objects, so even if you want to use this error-prone construct, you can't. Since I never use that construct with native variables, I don't mind not having it for class objects.

The other potential use of the return value from operator = is to allow statements such as a = b = c;, where the current value of c is assigned to b and the return value from that assignment is assigned to a. Although I don't use that construct either, since I find it more confusing than useful, I have been told that this return value is required to use some of the library facilities specified in the C++ standard. Therefore, it is my obligation to teach you the "right" way to write assignment operators so that you will be able to use these standard facilities with your classes.

Now we're up to the mysterious-looking construct operator =. This portion of the function declaration tells the compiler the name of the function we're defining; namely, operator =. The operator keyword lets the compiler know that the "name" of this function is actually an operator name, rather than a "normal" function name. We have to say operator = rather than merely =, for two reasons. First, because normal function names can't have a = character in them, but are limited to upper and lower case letters, numbers, and the underscore (_). Second, because when we're redefining any operator, even one like new whose name is made of characters allowed in identifiers, we have to tell the compiler that we're doing that on purpose. Otherwise, we'll get an error telling us that we're trying to define a function or variable with the same name as a keyword.[12]

[12] As this explanation may suggest, we can't make up our own operators with strange names by prefixing those names with operator; we're limited to those operators that already exist in the C++ language.

We're ready to look at the argument to this function, specified by the text inside the parentheses, const string& Str. We've already seen in Chapter 6 that & in this context means that the argument to which it refers is a reference argument rather than a value argument.[13] In other words, the variable Str is actually just another name for the argument provided by the caller of this function, rather than being a separate local variable with the same value as the caller's argument. However, there is a new keyword in this expression, const, which is short for "constant". In this context, it means that we promise that this function will not modify the argument to which const refers, namely string& Str. This is essential in the current situation, but it will take some discussion to explain why.

[13] In this section, you're going to see a lot of hedging of the form "in this context, x means y". The reason is that C and C++ both reuse keywords and symbols in many different situations, often with different meanings in each situation. In my opinion, this is a flaw in the design of these languages as it makes learning them more difficult. The reason for this reuse is that every time a keyword is added to the language, it's possible that formerly working code that contains a variable or function with the same name as the keyword will fail to compile. Personally, I think the problem of breaking existing code is overrated compared to the problems caused by overuse of the same keywords; however, I don't have a lot of old C or C++ code to maintain, so maybe I'm biased.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset