вказівник «this» у C++
Щоб зрозуміти вказівник «this», важливо знати, як об’єкти виглядають на функції та члени даних класу.
- Кожен об’єкт отримує власну копію елемента даних.
- Повний доступ до того самого визначення функції, яке є в сегменті коду.
Це означає, що кожен об’єкт отримує власну копію членів даних, і всі об’єкти спільно використовують одну копію функцій-членів.
Тепер питання полягає в тому, що якщо існує лише одна копія кожної функції-члена та використовується декількома об’єктами, як здійснюється доступ до відповідних членів даних і як вони оновлюються?
Компілятор надає неявний покажчик разом із іменами функцій як «this».
Покажчик «this» передається як прихований аргумент для всіх викликів нестатичних функцій-членів і доступний як локальна змінна в тілі всіх нестатичних функцій. Покажчик «this» недоступний у статичних функціях-членах, оскільки статичні функції-члени можна викликати без жодного об’єкта (з назвою класу).
Для класу X тип цього вказівника – «X*». Крім того, якщо функцію-член X оголошено як const, тоді тип цього вказівника є «const X *» (див. цей GFact )
У ранній версії C++ можна було змінити покажчик «this»; завдяки цьому програміст міг змінити об’єкт, над яким працював метод. Зрештою цю функцію було видалено, і тепер це в C++ є значенням r.
C++ дозволяє об’єктам знищувати себе, викликаючи наступний код:
delete> this> ;> |
Як сказав Страуструп, «це» може бути посиланням, ніж покажчиком, але посилання не було в ранній версії C++. Якщо «це» буде реалізовано як посилання, можна буде уникнути вищевказаної проблеми, і це буде безпечніше, ніж покажчик.
Нижче наведено ситуації, коли вказівник «цей» використовується:
1) Якщо ім’я локальної змінної збігається з ім’ям члена
#include> using> namespace> std;> > /* local variable is same as a member's name */> class> Test> {> private> :> > int> x;> public> :> > void> setX (> int> x)> > {> > // The 'this' pointer is used to retrieve the object's x> > // hidden by the local variable 'x'> > this> ->х = х;> > }> > void> print() { cout < <> 'x = '> < < x < < endl; }> };> > int> main()> {> > Test obj;> > int> x = 20;> > obj.setX(x);> > obj.print();> > return> 0;> }> |
Вихід:
x = 20
Для конструкторів, список ініціалізаторів також можна використовувати, якщо ім’я параметра збігається з ім’ям члена.
2) Повернути посилання на об’єкт, що викликає
/* Reference to the calling object can be returned */> Test& Test::func ()> {> > // Some processing> > return> *> this> ;> }> |
Коли повертається посилання на локальний об’єкт, повернуте посилання можна використовувати для ланцюгові виклики функцій на одному об'єкті.
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test(> int> x = 0,> int> y = 0) {> this> ->х = х;> this> ->y = y; }> > Test &setX(> int> a) { x = a;> return> *> this> ; }> > Test &setY(> int> b) { y = b;> return> *> this> ; }> > void> print() { cout < <> 'x = '> < < x < <> ' y = '> < < y < < endl; }> };> > int> main()> {> > Test obj1(5, 5);> > > // Chained function calls. All calls modify the same object> > // as the same object is returned by reference> > obj1.setX(10).setY(20);> > > obj1.print();> > return> 0;> }> |
Вихід:
x = 10 y = 20
Вправа:
Прогнозуйте вихід наступних програм. Якщо є помилки компіляції, виправте їх.
питання 1
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> public> :> > Test(> int> x = 0) {> this> ->х = х; }> > void> change(Test *t) {> this> = t; }> > void> print() { cout < <> 'x = '> < < x < < endl; }> };> > int> main()> {> > Test obj(5);> > Test *ptr => new> Test (10);> > obj.change(ptr);> > obj.print();> > return> 0;> }> |
Питання 2
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test(> int> x = 0,> int> y = 0) {> this> ->х = х;> this> ->y = y; }> > static> void> fun1() { cout < <> 'Inside fun1()'> ; }> > static> void> fun2() { cout < <> 'Inside fun2()'> ;> this> ->весело1(); }> };> > int> main()> {> > Test obj;> > obj.fun2();> > return> 0;> }> |
Питання 3
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test (> int> x = 0,> int> y = 0) {> this> ->х = х;> this> ->y = y; }> > Test setX(> int> a) { x = a;> return> *> this> ; }> > Test setY(> int> b) { y = b;> return> *> this> ; }> > void> print() { cout < <> 'x = '> < < x < <> ' y = '> < < y < < endl; }> };> > int> main()> {> > Test obj1;> > obj1.setX(10).setY(20);> > obj1.print();> > return> 0;> }> |
Питання 4
#include> using> namespace> std;> > class> Test> {> private> :> > int> x;> > int> y;> public> :> > Test(> int> x = 0,> int> y = 0) {> this> ->х = х;> this> ->y = y; }> > void> setX(> int> a) { x = a; }> > void> setY(> int> b) { y = b; }> > void> destroy() {> delete> this> ; }> > void> print() { cout < <> 'x = '> < < x < <> ' y = '> < < y < < endl; }> };> > int> main()> {> > Test obj;> > obj.destroy();> > obj.print();> > return> 0;> }> |