본문 바로가기

Programming/C++ Basic

[Basic C++] 21 - "this" Keyword in C++

The "this" keyword is one of the most useful keywords when it comes to object-oriented programming to deal with multiple objects. "this" is just a pointer variable to store the address of the current object. Let's recap how classes and objects work in C++ first shortly.

 

Figure 1 Class X and its objects

 

Figure 1 shows class X and its two objects. Class X has two class members variables and a class member function. As these class members are non-static, they are fully copied to the objects. Using "this" is an efficient method to access the address of a current object without writing more code to obtain it.

 


1. "this" stores the address of the current object

Code example 1

#include <iostream>

class X {
public:
	void func_x(X &obj) {
		std::cout << "[member function] The address of obj1 = " << &obj << std::endl;
	}
	X& obj_adr() {
		return *this;
	}
};

int main() {
	X obj1(10, 20);
	//std::cout << "The address of obj1 = " << &obj1.obj() << std::endl;
	std::cout << "[&obj1] The address of obj1 = " << &obj1 << std::endl;
	obj1.func_x(obj1);
	std::cout << "[this pointer] The address of obj1 = " << &obj1.obj_adr() << std::endl;
	std::cin.get();
}

Figure 2 Result of code example 2

The preceding example is a program that returns the address of "obj1" of class X. Three different ways to obtain the address are presented. The first is to use the reference operator (&) after the object is declared. The second is to use the member function (func_x) to accept the address of the object. The last is to use "this" keyword. The function inside class X "obj_adr" has the data type of X, thus it can use "this" pointer to obtain the address of the current object.

 


2. "this" helps the compiler clarify where each variable belongs to

The compiler can not differentiate function parameters and members variables unless they are explicitly clarified. The following example shows class X with a user-defined constructor accepting two parameters having the same names with the member variables.

 

Without telling the compiler that we are assigning the input values to the member variables, the compiler assigns the input parameters to themselves, thus nothing happens. To solve this problem, the member variables must be defined explicitly using "this" pointer.

 

Code example 2

#include <iostream>

class X {
private:
	int a = 0;
public:
	int b = 0;
	// If the names of constructor parameters and class members variables,
	// the compiler won't distinguish the variables properly.
	X(int a, int b) {
		this->a = a;
		this->b = b;
	}
	void print_members() {
		std::cout << a << " and " << b << std::endl;
	}
};
int main() {
	X obj1(10, 20);
	obj1.print_members();
}

Figure 3 Result of code example 2

 

There is another way to do the same using a member initializer list, and I highly recommend you to choose this way than using "this". This problem can be easily solved with a member initializer list or a different naming convention.


3. "this" pointer enables Method (member function) chaining

Method (member function) chaining is a syntax for calling multiple class member functions returning the address of a current object, thus they can all be declared within one statement. A method is another name of a member function in different programming languages such as Java and Python.

 

Code example 3

#include <iostream>

class Volume {
private:
	int vol = 0;
public:
	int width, height, length = 0;
	Volume (int w, int h, int l)
		:width(w), height(h), length(l)
	{}
	int get_vol() {
		return width * height * length;
	}
	Volume& set_w(int w) { width  = w; return *this; }
	Volume& set_h(int h) { height = h; return *this; }
	Volume& set_l(int l) { length = l; return *this; }

};
int main() {
	Volume v1(10, 20, 30);
	std::cout << "This volume is " << v1.get_vol() << std::endl;
    // Method Chanining
	v1.set_w(20).set_h(40).set_l(60);
	std::cout << "This volume is " << v1.get_vol() << std::endl;
}

Figure 4 Result of code example 4

The preceding example is a program to calculate the volume of an object with given parameters; width, length, and height. The variables are initialized by the member initializer list and the member function calculates and returns the volume.

 

There are also other three functions declared by the class type reference "Volume&" return *this (dereference of the current object reference). By doing so, these member functions can be called consecutively within one statement.

 

Figure 5 Method chaining

 

Figure 5 shows method chaining (member function chaining). Each non-static function returns *this to call another function.