This pointer



In addition to the explicit parameters in their argument lists, every class member function (method) receives an additional hidden parameter, the "this" pointer. The "this" pointer addresses the object on which the method was called. There are several cases when the "this" pointer is absolutely required to implement desired functionality within class methods.

Implicit Use of this Pointer



Each object maintains its own set of data members, but all objects of a class share a single set of methods. This is, a single copy of each method exists within the machine code that is the output of compilation and linking. A natural question is then if only a single copy of each method exists, and its used by multiple objects, how are the proper data members accessed and updated. The compiler uses the "this" pointer to internally reference the data members of a particular object. Suppose, we have an Employee class that contains a salary member and a setSalary method to update it. Now, suppose that two Employees are instantiated
class Employee
{
public:
....
void setSalary(double sal)
{
salary = sal;
}
private:
....
double salary;
....
}

int main()
{
....
Employee programmer;
Employee janitor;

janitor.setSalary(60000.0);
programmer.setSalary(40000.0);
....
}

If only one setSalary method exists within the binary that is running, how is the correct Employee's salary updated? The compiler uses the "this" pointer to correctly identify the object and its members. During compilation, the compiler inserts code for the "this" pointer into the function. The setSalary method that actually runs is similar to the following pseudo-code.


void setSalary(Employee *this, float sal)
{
this->salary = sal;
}


Explicit Use of this Pointer

Concatenating Calls

Explicit use of the "this" pointer allows the concatenation of calls on an object. Suppose we have a class used to represent a point in 2D space. We will store the x and y coordinates and have several methods to manipulate the point. For simplicity, we will only code setX, setY and doubleMe methods. The doubleMe method will double both the X and Y coordinates. Here's a first version of the class
class Point
{
public:
void setX(int x) {_x = x;}
void setY(int y) {_y = y;}
void doubleMe()
{
_x *= 2;
_y *= 2;
}
private:
int _x;
int _y;
};

To use this class, we would code something like this.
Point Lower;
Lower.SetX(20);
Lower.SetY(30);
Lower.doubleMe();

A more natural way to handle this series of operations on a single point object would be to concatenate the calls.

How can we get this to work? The member access operators, dot, ".", and arrow, "->", are left associative. That means that the above expression is evaluated from left to right.
((lower.setX(50)).setY(20)).doubleMe();


That is, "setY(30)" is called on the result of lower.setX(20). If lower.setX(20) returned an object of the class point rather than void, we would have what we need. Likewise, if (lower.setX(20)).setY(30) returned an object of class point as well, then doubleMe() could be called on the result. This can be accomplished with the "this" pointer. We code each method to return a reference to an object of the class type. We return a reference rather than a copy for efficiency. Here is an updated version of the Point class that supports concatenation of calls.

Program Using Reference

#include<stdio.h>

class Point
{
public:
Point& setX(int x)
{
_x = x;
return *this;
}
Point& setY(int y)
{
_y = y;
return *this;
}
Point& doubleMe()
{
_y *= 2;
_x *= 2;
printf("%d",_y+_x);
return *this;
}
private:
int _x;
int _y;
};

void main()
{
Point lower;
(((lower.setX(50)).setY(20)).doubleMe());
}

Program Using Pointers


#include<stdio.h>

class Point
{
public:
Point* setX(int x)
{
_x = x;
return this;
}
Point* setY(int y)
{
_y = y;
return this;
}
Point* doubleMe()
{
_y *= 2;
_x *= 2;
printf("%d",_y+_x);
return this;
}
private:
int _x;
int _y;
};

void main()
{
Point lower;
((lower.setX(50))->setY(20))->doubleMe();
}


Resolving Ambiguities

The "this" pointer is also useful if it is desired to use the same identifier for both a local variable within a method and for a class member. Let's look at the class in the last example, Point. Suppose that rather than use "_x" and "_y", the members used to represent the coordinates of the "point" are "x" and "y". Further suppose that we want to use the identifiers "x" and "y" in the parameter list of the methods setX() and setY(). This is not unreasonable. After all, there is only a single x coordinate and a single y coordinate. Why complicate things with multiple identifiers. Within the methods, the local x and y will mask (override) the "x" and "y" class members. The "this" pointer can be used to access the class members in this case


class Point
{
public:
Point& setX(int x)
{
this->x = x;
// The "this" pointer allows access to the class member
return *this;
}
Point& setY(int y)
{
this->y = y;
return *this;
}
Point& doubleMe()
{
x *= 2;
y *= 2;
// x and y refer to the class members.
return *this;
}
private:
int x;
int y;
};

Notice that the "this" pointer is not required within the doubleMe method. There is no ambiguity.


Self Identification

When implementing some methods, it is important to check for identity. The classic example is a copy assignment operator for a class that has some dynamically allocated members. For example, using the employee class defined earlier:

Employee janitor;
Employee programmer;
Employee manager;

manager = janitor + programmer;


class Employee {
public:
Employee(char employeename[]);
Employee& operator=(const Employee &);
....
private:
char *name;
};

Employee::Employee(char employeename[])
{
name = new char[sizeof(employeename) + 1];
strcpy(name,employeename);
}

Employee& Employee::operator=(const Employee& rhs)
{
delete [] name;
name = new char[sizeof(rhs.name) + 1];
strcpy(name,rhs.name);

return *this;
}

int main()
{
.....
Employee a("John");
Employee b("Janitor");
....
a = b;
.....
}

There's a very subtle problem with this implementation. It's fine the way it's used in the above program, but what if the following error is made.
a=a;
That is, an Employee object is assigned to itself. This is unlikely to occur directly, but if the objects were stored in an array or list or referenced by pointers it could happen. The first step in the assignment operator deletes the name buffer. The sizeof operation in the next line will bomb. "rhs.name" has been deleted. The program will die. A simple check for identity using the "this" pointer will prevent this.


Employee& Employee::operator=(const Employee& rhs)
{
if (this != &rhs)
{
delete [] name;
name = new char[sizeof(rhs.name) + 1];
strcpy(name,rhs.name);
}
return *this;
}

0 comments