Flylib.com

Books Software

 
 
 

Section 10.5. Using the this Pointer


[Page 545]

10.5. 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

<iostream>
 4

using

std::cout;
 5

using

std::endl;
 6
 7

class

Test
 8  {
 9

public

:
10     Test(

int

=


);

// 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 <<

"\n this->x = "

<<

this

->x;

33
34


// explicitly use the dereferenced this pointer and


35


// the dot operator to access the member x


36

cout <<

"\n(*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



;
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).


[Page 546]

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.


[Page 547]

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

=


,

int

=


,

int

=


);

// 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

<iostream>
 4

using

std::cout;
 5
 6

#include

<iomanip>
 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 >=


&& h <

24

) ? h :


;

// 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 >=


&& m <

60

) ? m :


;

// 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 >=


&& s <

60

) ? s :


;

// 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 ==


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

<iostream>
 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 <<

"\nStandard time: "

;
21     t.printStandard();
22
23     cout <<

"\n\nNew standard time: "

;
24
25


// cascaded function calls


26

t.setTime(

20

,

20

,

20

).printStandard();

27     cout << endl;
28

return



;
29  }

// end main


Universal time: 18:30:22
 Standard time: 6:30:22 PM

 New standard time: 8:20:20 PM



{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}

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.