Using the this Pointer

We have seen that an object's member functions can manipulate the object's data. How do member functions know which object's data members to manipulate? Every object has access to its own address through a pointer called this (a C++ keyword). An object's this pointer is not part of the object itselfi.e., the size of the memory occupied by the this pointer is not reflected in the result of a sizeof operation on the object. Rather, the this pointer is passed (by the compiler) as an implicit argument to each of the object's non-static member functions. Section 10.7 introduces static class members and explains why the this pointer is not implicitly passed to static member functions.

Objects use the this pointer implicitly (as we have done to this point) or explicitly to reference their data members and member functions. The type of the this pointer depends on the type of the object and whether the member function in which this is used is declared const. For example, in a nonconstant member function of class Employee, the this pointer has type Employee * const (a constant pointer to a nonconstant Employee object). In a constant member function of the class Employee, the this pointer has the data type const Employee * const (a constant pointer to a constant Employee object).

Our first example in this section shows implicit and explicit use of the this pointer; later in this chapter and in Chapter 11, we show some substantial and subtle examples of using this.

Implicitly and Explicitly Using the this Pointer to Access an Object's Data Members

Figure 10.17 demonstrates the implicit and explicit use of the this pointer to enable a member function of class Test to print the private data x of a Test object.

Figure 10.17. this pointer implicitly and explicitly accessing an object's members.

(This item is displayed on pages 545 - 546 in the print version)

 1 // Fig. 10.17: fig10_17.cpp
 2 // Using the this pointer to refer to object members.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 class Test
 8 {
 9 public:
10 Test( int = 0 ); // default constructor
11 void print() const;
12 private:
13 int x;
14 }; // end class Test
15
16 // constructor
17 Test::Test( int value )
18 : x( value ) // initialize x to value
19 {
20 // empty body
21 } // end constructor Test
22
23 // print x using implicit and explicit this pointers;
24 // the parentheses around *this are required
25 void Test::print() const
26 {
27 // implicitly use the this pointer to access the member x
28 cout << " x = " << x; 
29
30 // explicitly use the this pointer and the arrow operator
31 // to access the member x 
32 cout << "
 this->x = " << this->x; 
33
34 // explicitly use the dereferenced this pointer and
35 // the dot operator to access the member x 
36 cout << "
(*this).x = " << ( *this ).x << endl; 
37 } // end function print
38
39 int main()
40 {
41 Test testObject( 12 ); // instantiate and initialize testObject
42
43 testObject.print();
44 return 0;
45 } // end main
 
 x = 12
 this->x = 12
 (*this).x = 12
 

For illustration purposes, member function print (lines 2537) first prints x by using the this pointer implicitly (line 28)only the name of the data member is specified. Then print uses two different notations to access x tHRough the this pointerthe arrow operator (->) off the this pointer (line 32) and the dot operator (.) off the dereferenced this pointer (line 36).


Note the parentheses around *this (line 36) when used with the dot member selection operator (.). The parentheses are required because the dot operator has higher precedence than the * operator. Without the parentheses, the expression *this.x would be evaluated as if it were parenthesized as *( this.x), which is a compilation error, because the dot operator cannot be used with a pointer.

One interesting use of the this pointer is to prevent an object from being assigned to itself. As we will see in Chapter 11, self-assignment can cause serious errors when the object contains pointers to dynamically allocated storage.


Common Programming Error 10.7

Attempting to use the member selection operator (.) with a pointer to an object is a compilation errorthe dot member selection operator may be used only with an lvalue such as an object's name, a reference to an object or a dereferenced pointer to an object.

 

Using the this Pointer to Enable Cascaded Function Calls

Another use of the this pointer is to enable cascaded member-function calls in which multiple functions are invoked in the same statement (as in line 14 of Fig. 10.20). The program of Figs. 10.1810.20 modifies class Time's set functions setTime, setHour, setMinute and setSecond such that each returns a reference to a Time object to enable cascaded member-function calls. Notice in Fig. 10.19 that the last statement in the body of each of these member functions returns *this (lines 26, 33, 40 and 47) into a return type of Time &.

Figure 10.18. Time class definition modified to enable cascaded member-function calls.

(This item is displayed on pages 547 - 548 in the print version)

 1 // Fig. 10.18: Time.h
 2 // Cascading member function calls.
 3
 4 // Time class definition.
 5 // Member functions defined in Time.cpp.
 6 #ifndef TIME_H
 7 #define TIME_H
 8
 9 class Time
10 {
11 public:
12 Time( int = 0, int = 0, int = 0 ); // default constructor
13
14 // set functions (the Time & return types enable cascading)
15 Time &setTime( int, int, int ); // set hour, minute, second
16 Time &setHour( int ); // set hour 
17 Time &setMinute( int ); // set minute 
18 Time &setSecond( int ); // set second 
19
20 // get functions (normally declared const)
21 int getHour() const; // return hour
22 int getMinute() const; // return minute
23 int getSecond() const; // return second
24
25 // print functions (normally declared const)
26 void printUniversal() const; // print universal time
27 void printStandard() const; // print standard time
28 private:
29 int hour; // 0 - 23 (24-hour clock format)
30 int minute; // 0 - 59
31 int second; // 0 - 59
32 }; // end class Time
33
34 #endif

Figure 10.19. Time class member-function definitions modified to enable cascaded member-function calls.

(This item is displayed on pages 548 - 549 in the print version)

 1 // Fig. 10.19: Time.cpp
 2 // Member-function definitions for Time class.
 3 #include 
 4 using std::cout;
 5
 6 #include 
 7 using std::setfill;
 8 using std::setw;
 9
10 #include "Time.h" // Time class definition
11
12 // constructor function to initialize private data;
13 // calls member function setTime to set variables;
14 // default values are 0 (see class definition)
15 Time::Time( int hr, int min, int sec )
16 {
17 setTime( hr, min, sec );
18 } // end Time constructor
19
20 // set values of hour, minute, and second
21 Time &Time::setTime( int h, int m, int s ) // note Time & return
22 {
23 setHour( h );
24 setMinute( m );
25 setSecond( s );
26 return *this; // enables cascading
27 } // end function setTime
28
29 // set hour value
30 Time &Time::setHour( int h ) // note Time & return
31 {
32 hour = ( h >= 0 && h < 24 ) ? h : 0; // validate hour
33 return *this; // enables cascading
34 } // end function setHour
35
36 // set minute value
37 Time &Time::setMinute( int m ) // note Time & return
38 {
39 minute = ( m >= 0 && m < 60 ) ? m : 0; // validate minute
40 return *this; // enables cascading
41 } // end function setMinute
42
43 // set second value
44 Time &Time::setSecond( int s ) // note Time & return
45 {
46 second = ( s >= 0 && s < 60 ) ? s : 0; // validate second
47 return *this; // enables cascading
48 } // end function setSecond
49
50 // get hour value
51 int Time::getHour() const
52 {
53 return hour;
54 } // end function getHour
55
56 // get minute value
57 int Time::getMinute() const
58 {
59 return minute;
60 } // end function getMinute
61
62 // get second value
63 int Time::getSecond() const
64 {
65 return second;
66 } // end function getSecond
67
68 // print Time in universal-time format (HH:MM:SS)
69 void Time::printUniversal() const
70 {
71 cout << setfill( '0' ) << setw( 2 ) << hour << ":"
72 << setw( 2 ) << minute << ":" << setw( 2 ) << second;
73 } // end function printUniversal
74
75 // print Time in standard-time format (HH:MM:SS AM or PM)
76 void Time::printStandard() const
77 {
78 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
79 << ":" << setfill( '0' ) << setw( 2 ) << minute
80 << ":" << setw( 2 ) << second << ( hour < 12 ? " AM" : " PM" );
81 } // end function printStandard

Figure 10.20. Cascading member-function calls.

(This item is displayed on page 550 in the print version)

 1 // Fig. 10.20: fig10_20.cpp
 2 // Cascading member function calls with the this pointer.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include "Time.h" // Time class definition
 8
 9 int main()
10 {
11 Time t; // create Time object
12
13 // cascaded function calls 
14 t.setHour( 18 ).setMinute( 30 ).setSecond( 22 );
15
16 // output time in universal and standard formats
17 cout << "Universal time: ";
18 t.printUniversal();
19
20 cout << "
Standard time: ";
21 t.printStandard();
22
23 cout << "

New standard time: ";
24
25 // cascaded function calls 
26 t.setTime( 20, 20, 20 ).printStandard();
27 cout << endl;
28 return 0;
29 } // end main
 
 Universal time: 18:30:22
 Standard time: 6:30:22 PM

 New standard time: 8:20:20 PM
 

The program of Fig. 10.20 creates Time object t (line 11), then uses it in cascaded member-function calls (lines 14 and 26). Why does the technique of returning *this as a reference work? The dot operator (.) associates from left to right, so line 14 first evaluates t.setHour( 18 ) then returns a reference to object t as the value of this function call. The remaining expression is then interpreted as

t.setMinute( 30 ).setSecond( 22 );

The t.setMinute( 30 ) call executes and returns a reference to the object t. The remaining expression is interpreted as

t.setSecond( 22 );

Line 26 also uses cascading. The calls must appear in the order shown in line 26, because printStandard as defined in the class does not return a reference to t. Placing the call to printStandard before the call to setTime in line 26 results in a compilation error. Chapter 11 presents several practical examples of using cascaded function calls. One such example uses multiple << operators with cout to output multiple values in a single statement.





C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627
Simiral book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net