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