The ‘this’ Pointer In C++
Every non-static member function of a class, struct, or union automatically receives this pointer, which is a special, implicit, and constant pointer in C++. It indicates which particular object called the member function.
The following are the main aspects of this pointer:
Type of this Pointer
- The type of this for a class X non-const member function is X* const. You cannot alter the object to which this points because it is a constant pointer to an object of type X. However, this allows you to change the item it references to.
- For a class X const member function, this is const X* const. The pointer and object it points to cannot be modified because they are constant.
Implicit and Explicit Use
- Implicit Use: This assumes that every direct reference to a member inside a member function is an implicit reference. In a Sales_data member function, for instance, bookNo is implicitly this->bookNo.
- Explicit Use: It is acceptable to use this->member explicitly, even if it is frequently unnecessary. To distinguish between a member name and a local variable or parameter of the same name, explicit use is frequently used. This->a = a;, for example, gives the class member a the parameter a.
Common Practical Applications
- Returning the Invoking Object: Returning the object by reference (return *this;) from member methods is crucial, especially with overloaded assignment operators. Chained assignments (obj1 = obj2 = obj3) are possible without temporary objects.
- Preventing Self-Assignment: If (this!= &rhs) is used in overloaded assignment operators to check for self-assignment to minimise crashes or data loss, such as freeing memory before copying it.
Limitations and Behavior
- Non-Static Member Functions Only: This pointer is only available in member functions that are not static. This pointer is absent from friend functions and static member functions.
- Illegal to Define this:: Programmers are prohibited from explicitly defining a variable or parameter with this name.
- Rvalue Property:: Since this is regarded as a rvalue, it cannot be assigned a new value or have its address changed.
Code Example: Overloading the Assignment Operator with Class Definition
The usage of this pointer in an overloaded assignment operator to prevent self-assignment and permit chaining is illustrated in the example that follows:
#include <iostream> // Required for std::cout, std::endl
#include <string> // Required for std::string (though not directly used in Foo, good to have if main uses it)
#include <iomanip> // Required for std::fixed, std::setprecision (if your main used previous examples)
// Class Definition (from your previous snippet)
class Foo {
private:
int x;
public:
Foo(int val = 0) : x(val) {}
void show_x() const {
std::cout << "x = " << x << std::endl;
}
Foo& operator=(const Foo &RHS) {
if (this != &RHS) {
this->x = RHS.x;
}
return (*this);
}
};
// The main function (from your previous snippet)
int main() {
Foo obj1(10);
Foo obj2;
Foo obj3;
std::cout << "Before assignment:" << std::endl;
obj1.show_x(); // Output: x = 10
obj2.show_x(); // Output: x = 0
obj3.show_x(); // Output: x = 0
// Chained assignment using the overloaded operator=
// obj3 = (obj2 = obj1);
obj3 = obj2 = obj1;
std::cout << "\nAfter assignment:" << std::endl;
obj1.show_x(); // Output: x = 10
obj2.show_x(); // Output: x = 10
obj3.show_x(); // Output: x = 10
// Demonstrate self-assignment, which is safely handled by the 'if (this != &RHS)' check
obj1 = obj1;
std::cout << "\nAfter self-assignment (obj1 = obj1):" << std::endl;
obj1.show_x(); // Output: x = 10 (value remains consistent)
return 0;
}
Output
Before assignment:
x = 10
x = 0
x = 0
After assignment:
x = 10
x = 10
x = 10
After self-assignment (obj1 = obj1):
x = 10
You can also read Destructors In C++: The Cleanup Code For Your Objects