Ключевое слово this представляет указатель на текущий объект данного класса. Соответственно через this мы можем обращаться внутри класса к любым его членам.
#include <iostream> class Point { public: Point(int x, int y) { this->x = x; this->y = y; } void showCoords() { std::cout << "Point x: " << this->x << "\t y: " << y << std::endl; } private: int x; int y; }; int main() { Point p1{20, 50}; p1.showCoords(); }
В данном случае определен класс Point, который представляет точку на плоскости. И для хранения координат точки в классе определены переменные x и y.
Для обращения к переменным используется указатель this. Причем после this ставится не точка, а стрелка ->.
В большинстве случаев для обращения к членам класса вряд ли поднадобится ключевое слово this. Но оно может быть необходимо, если параметры функции или переменные, которые определяются внутри функции, называются также как и переменные класса. К примеру, чтобы в конструкторе разграничить параметры и переменные класса как раз и используется указатель this.
Другое практическое применение this - с его помощью можно возвращать текущий объект класса:
#include <iostream> class Point { public: Point(int x, int y) { this->x = x; this->y = y; } void showCoords() { std::cout << "Coords x: " << x << "\t y: " << y << std::endl; } Point &move(int x, int y) { this->x += x; this->y += y; return *this; } private: int x; int y; }; int main() { Point p1{20, 50}; p1.showCoords(); // Point x: 20 y: 50 p1.move(10, 5).move(10, 10); p1.showCoords(); // Point x: 40 y: 65 }
Здесь метод move с помощью указателя this возвращает ссылку на объект текущего класса, осуществляя условное перемещение точки. Таким образом, мы можем по цепочке для одного и того же объекта вызывать метод move:
p1.move(10, 5).move(10);
Здесь также важно отметить возвращение не просто объекта Point, а ссылки на этот объект. Так, в данном случае выге определенная строка фактически будет аналогично следующему коду:
p1.move(10, 5); p1.move(10, 10);
Но если бы метод move возвращал бы не ссылку, а посто объект:
Point move(int x, int y) { this->x += x; this->y += y; return *this; }
То вызов p1.move(10, 5).move(10)
был бы фактически эквивалентен следующему коду:
Point temp = p1.move(10, 5); temp.move(10, 10);
Где второй вызов метода move вызывался бы для временной копии и никак бы не затрагивал переменную p1.
В качестве альтернативы можно возвращать сам указатель this:
#include <iostream> class Point { public: Point(int x, int y) { this->x = x; this->y = y; } void showCoords() { std::cout << "Point x: " << this->x << "\t y: " << y << std::endl; } Point* move(int x, int y) { this->x += x; this->y += y; return this; } private: int x; int y; }; int main() { Point p1{20, 50}; p1.showCoords(); // Point x: 20 y: 50 p1.move(10, 5)->move(10, 10)->move(10, 15); p1.showCoords(); // Point x: 50 y: 80 }
В данном случае, поскольку функция move()
возвращает указатель this, то у результата функции мы также можем вызвать функцию move
через операцию ->
:
p1.move(10, 5)->move(10, 10)->move(10, 15)
Другой пример:
#include <iostream> class Integer { public: Integer(int number) { value=number; } Integer& add(const Integer& obj) { value += obj.value; return *this; } Integer& subtract(const Integer& obj) { value -= obj.value; return *this; } Integer& multiply(const Integer& obj) { value *= obj.value; return *this; } void print() const { std::cout << "Value: " << value << std::endl; } private: int value; }; int main() { Integer num{10}; num.add(Integer{30}).subtract(Integer{15}).multiply(Integer{2}); num.print(); // Value: 50 }
Здесь класс Integer представляет условно целое число, которое хранится в переменной value. В нем определены функции add() (сложение), subtract() (вычитание), и multiply() (умножение), которые принимают другой объект Integer и выполняеют соответствующую операцию между текущим объектом и аргументом. Причем каждая из этих функций возвращает текущий объект, благодаря чему эти функции можно было выполнить по цепочке:
Integer num{10}; num.add(Integer{30}).subtract(Integer{15}).multiply(Integer{2});