home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

C++ in Plain English
(Publisher: IDG Books Worldwide, Inc.)
Author(s): Brian Overland
ISBN: 1558284729
Publication Date: 04/01/96

Bookmark It

Search this book:
 
Previous Table of Contents Next


In either case, the two statements in the body of the function definition are almost trivial. The first statement calls the cpy function, which already exists, to do the copying. The second statement returns the object itself—that is, the same CStr object that is the target of the assignment in effect, the statement return *this says:

    Return myself!

Figure 7.5 illustrates how C++ translates an assignment expression. Note that this function is called through str1, the left operand. This fact becomes important in the next section, when we look more closely at the this keyword.


Figure 7.5  Translation of an assignment expression.

The this Pointer and Its Uses

Within a member function, the this keyword is a pointer to the current object. (By “current object,” I mean the object through which the function was called.) Every time you call a member function, C++ passes a hidden this pointer as an argument (see Figure 7.6).


Figure 7.6  The “this” pointer as used with the CStr class.

Within the member-function definition, references to a data member are automatically translated into object-member references using the this pointer, as shown in Table 7. 1. Many member functions never use the this pointer, because its use within the function is implicit.

Table 7.1 Implicit use of “this” pointer.
Data member reference Translated in a member function to:
pData this->pData
nLength this->nLength

Sometimes you need to refer explicitly to the object, and then using this is necessary. Such is the case with assignment functions. Assignment expressions in C and C++ return a value: that of the left operand. The fact that assignments return a value makes possible the following kinds of statements:

int     x, y, z;
CString stringA, stringB, stringC;

x = y = z = 0;
stringA = stringB = stringC = “hello!”;

After “hello!” is assigned to stringC, the expression stringC = “hello” returns the resulting value of the stringC, which is then assigned to stringB. An assignment function must therefore return the value of the left operand after it is assigned a value. The consequence for writing the code is this: the final task of the assignment function must do is return the value of the left operand.

But remember that the assignment function is called as a member function of the left operand. The left operand is the current object (the object through which the function was called). Therefore—if you’re still following me—in implementing assignment, the final task of an object is to return itself. Here’s how you express this idea in C++:

    return *this;

Earlier I said that this is a pointer to the current object. Therefore, *this refers to the object itself.

Assignments and the Reference Operator (&)

The reference operator (&) is necessary in assignment operator syntax, because it is the only way to support assignment operator syntax (which uses values and not pointers to the objects) and yet do so efficiently. C++ carries out a multiple assignment statement by transferring data from one object to another without creating extra copies. Were it not for the reference operator, many extra copies would have to be made and then thrown away.

Figure 7.7 illustrates how assignment between two CStr objects would work. The return value is a pointer to the object on the left. (In source code, a value is returned, but the reference operator causes the compiler to implement this by returning a pointer.) In multiple assignment, the pointer returned would immediately become the argument for the next assignment to be performed.


Figure 7.7  Mechanics of a CStr assignment.

Writing a Conversion Function

The CStr class is now extremely flexible and easy to use. You can, for example, use it to concatenate and assign expressions, just as with strings in Basic.

CStr first = “Norma”
CStr middle = “Jean”
CStr last = “Baker”
CStr name;

name = first + “ ” + middle + “ ” + last;

Before we leave the CStr example, there’s at least one other ability it would be useful to give it. In the best of all worlds, you should to be able to use the class wherever char* is expected. For example, puts is one of many standard library functions that take a char* argument. It would be convenient to pass a CStr object to this function and have it print the contents, just as it would with a char* argument.

#include <stdio.h>

CStr warn = “This is your final warning”;
puts(warn);                // puts takes a char* argument

In C++, you can get this functionality by writing a conversion function. This function tells the compiler how to convert an object of the class to another type. It’s easy to get confused here, because as I pointed out in Chapter 6, constructors also perform conversion. But there’s no contradiction. Whether the compiler calls a conversion function or a constructor depends on the direction of the conversion.

For any given class, conversion functions handle outgoing conversions (convert to another type). Constructors handle incoming conversions (convert from another type).


Figure 7.8  Conversion and constructor functions compared.

The conversion function is a member function declared as follows within the class declaration. The declaration has no return type and no arguments.

   operator type ()

Converting from a CStr object to char* is easy, because all the function has to do is to extract the data pointer. The following code declares a conversion function within the CStr class declaration. Function inlining is used because the definition is so short.

class CStr {
   ...
   operator const char*() {return get();}
};

I used const char* as the conversion type here rather than char*. These types are the same except that the result of a const char* conversion cannot be modified in code, and it can be passed only to a function taking a const char* argument. The bottom line is that CStr objects can be given as arguments where const char* is expected but not where a simple char* is expected.

Most string-handling functions in the standard C++ library (including puts) take a const char* argument unless they write to the string, in which case they take a char* argument. Because of the way memory allocation works in CStr, it would be dangerous to allow direct modification of the string data through the pointer to the actual memory block (pData). The fact that the conversion is to const char* prevents such direct modification.


Previous Table of Contents Next
[an error occurred while processing this directive]

Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.