this
PointerThere’s only one copy of each class’s functionality, but there can be many objects of a class, so 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). The this
pointer is not part of the object itself—i.e., 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 9.15 introduces static
class members and explains why the this
pointer is not implicitly passed to static
member functions.
this
Pointer to Avoid Naming CollisionsMember functions use the this
pointer implicitly (as we’ve done so far) or explicitly to reference an object’s data members and other member functions. A common explicit use of the this
pointer is to avoid naming conflicts between a class’s data members and member-function parameters (or other local variables). If a member function contains a local variable and data member with the same name, as in the following setHour
function:
// set hour value
void Time::setHour(int hour) {
if (hour >= 0 && hour < 24) {
this->hour = hour; // use this-> to access data member
}
else {
throw invalid_argument("hour must be 0-23");
}
}
the local variable is said to hide or shadow the data member—using just the variable name in the member function’s body refers to the local variable rather than the data member. However, you can access the data member hour
by qualifying its name with this->
. So the following statement assigns the hour
parameter’s value to the data member hour
this->hour = hour; // use this-> to access data member
A widely accepted practice to minimize the proliferation of identifier names is to use the same name for a set function’s parameter and the data member it sets, and to reference the data member in the set function’s body via this->
.
this
PointerThe 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
:
In a non-const
member function of class Employee
, the this
pointer has the type Employee*
const
—a constant pointer to a nonconstant Employee.
In a const
member function, this
has the type const
Employee*
const
—a constant pointer to a constant Employee
.
this
Pointer to Access an Object’s Data MembersFigure 9.24 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. In the next example and in Chapter 10, we show some substantial and subtle examples of using this
.
For illustration purposes, member function print
(lines 19–30) first prints x
by using the this
pointer implicitly (line 21)—only the name of the data member is specified. Then print
uses two different notations to access x
through the this
pointer—the arrow operator (->
) off the this
pointer (line 25) and the dot operator (.
) off the dereferenced this
pointer (line 29). Note the parentheses around *this
(line 29) 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’ll see in Chapter 10, self-assignment can cause serious errors when the object contains pointers to dynamically allocated storage.
this
Pointer to Enable Cascaded Function CallsAnother use of the this
pointer is to enable cascaded member-function calls—that is, invoking multiple functions sequentially in the same statement (as in line 10 of Fig. 9.27). The program of Figs. 9.25–9.27 modifies class Time
’s set functions setTime
, setHour
, setMinute
and setSecond
such that each returns a reference to the Time
object on which it’s called to enable cascaded member-function calls. Notice in Fig. 9.26 that the last statement in the body of each of these member functions returns *this
(lines 21, 33, 45 and 57) into a return type of Time&
.
The program of Fig. 9.27 creates Time
object t
(line 8), then uses it in cascaded member-function calls (lines 10 and 18). Why does the technique of returning *this
as a reference work? The dot operator (.
) associates from left to right, so line 10
t.setHour(18).setMinute(30).setSecond(22);
first evaluates t.setHour(18)
, then returns a reference to (the updated) 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 (further updated) object t
. The remaining expression is interpreted as
t.setSecond(22);
Line 18 (Fig. 9.27) also uses cascading. Note that we cannot chain another Time
member-function call after toStandardString
here, because it does not return a reference to t
—we could, however, place a call to a string
member function, because toStandardString
returns a string
. Placing the call to toStandardString
before the call to setTime
in line 18 results in a compilation error, because the string
returned by toStandardString
does not have a setTime
function. Chapter 10 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.