Вариант использования 'этого' указателя в C++

Я понимаю значение 'этого', но я не вижу варианта использования его.

Для следующего примера я должен преподавать компилятор, если параметр совпадает с членской переменной, и мне нужен этот указатель.

#include <iostream>

using namespace std;

class AAA {
    int x;
public:
    int hello(int x) { this->x = x;}
    int hello2(int y) {x = y;} // same as this->x = y
    int getx() {return x;}
};

int main()
{
   AAA a;
   a.hello(10); // x <- 10
   cout << a.getx();
   a.hello2(20); // x <- 20
   cout << a.getx();
}

Каков был бы вариант использования для 'этого' указателя кроме этого (изобретенного) примера?

Добавленный

Спасибо за все ответы. Даже при том, что я делаю ответ orangeoctopu, как принято один, это просто, потому что он получил большую часть голосования. Я должен сказать, что все ответы довольно полезны, и дают мне лучше понимание.

7
задан prosseek 23 July 2010 в 20:37
поделиться

14 ответов

Иногда вы хотите вернуть себя из оператора, например operator =

MyClass& operator=(const MyClass &rhs) {
     // assign rhs into myself

     return *this;
}
12
ответ дан 6 December 2019 в 04:50
поделиться

В C++ он используется не очень часто. Однако очень часто используется, например, в Qt, где вы создаете виджет, который имеет текущий объект в качестве родителя. Например, окно создает кнопку в качестве своего дочернего объекта:

QButton *button = new QButton(this);
3
ответ дан 6 December 2019 в 04:50
поделиться

Указатель this полезен, если методу класса необходимо передать экземпляр (this) другой функции.

12
ответ дан 6 December 2019 в 04:50
поделиться

Указатель this - это указатель на сам объект. Рассмотрим, например, следующий метод:


class AAA {
    int x;
public:
    int hello(int x) { some_method(this, x);}
};
1
ответ дан 6 December 2019 в 04:50
поделиться

Вы можете удалить динамически созданный объект, вызвав delete this из одной из его функций-членов.

2
ответ дан 6 December 2019 в 04:50
поделиться

Кроме получения указателя на собственный объект для передачи (или возврата) другим функциям, и решения, что идентификатор является членом, даже если он скрыт локальной переменной, есть действительно надуманное использование этого в шаблонном программировании. Это использование заключается в преобразовании не зависимого имени в зависимое. Шаблоны проверяются в два захода, сначала перед фактической подстановкой типов, а затем снова после подстановки типов.

Если вы объявляете шаблонный класс, производный от одного из параметров его типа, вам необходимо квалифицировать доступ к членам базового класса так, чтобы компилятор обошел проверку на первом этапе и оставил проверку на второй этап:

template <typename T>
struct test : T {
   void f() {
      // print();    // 1st pass Error, print is undefined
      this->print(); // 1st pass Ok, print is dependent on T
   }
};
struct printer {
   void print() { std::cout << "print"; }
};
struct painter { 
   void paint() { std::cout << "paint"; }
};
int main() {
   test<printer> t;  // Instantiation, 2nd pass verifies that test<printer>::print is callable
   t.f();
   //test<painter> ouch; // 2nd pass error, test<painter>::print does not exist
}

Важный момент: поскольку test наследуется от T, все ссылки на this зависят от аргумента шаблона T, и поэтому компилятор предполагает, что он корректен, и оставляет проверку на второй этап. Есть и другие решения, например, фактически квалифицировать тип, реализующий метод, как в:

template <typename T>
struct test2 : T {
   void f() {
      T::print(); // 1st pass Ok, print is dependent on T
   }
};

Но это может иметь нежелательный побочный эффект: компилятор будет статически диспетчеризировать вызов printer::print независимо от того, является ли printer виртуальным методом или нет. Таким образом, поскольку printer::print объявлен виртуальным, если класс, производный от test, реализует print, то будет вызван этот конечный переопределитель, в то время как если бы тот же класс был производным от test2, то код вызвал бы printer::print.

// assumes printer::print is virtual
struct most_derived1 : test<printer> {
   void print() { std::cout << "most derived"; }
};
struct most_derived2 : test2<printer> {
   void print() { std::cout << "most derived"; }
};
int main() {
   most_derived1 d1;
   d1.f();          // "most derived"
   most_derived2 d2;
   d2.f();          // "print"
}
3
ответ дан 6 December 2019 в 04:50
поделиться
void somefunc(AAA* a_p)
{
   ......
}

class AAA { 
    int x; 
public: 
    int hello(int x) { this->x = x;} 
    int hello2(int y) {x = y;} // same as this.x = y 
    int getx() {return x;} 
    void DoSomething()   { somefunc(this);   }
};
1
ответ дан 6 December 2019 в 04:50
поделиться

this неявно, когда вы используете функцию-член или переменную без указания. Кроме этого, существует много, много ситуаций, в которых вы захотите передать текущий объект другой функции или в качестве возвращаемого значения.

Так что, да, это весьма полезно.

1
ответ дан 6 December 2019 в 04:50
поделиться

Иногда вам нужно обратиться к самому объекту "this", а иногда вам может понадобиться разобрать случаи, когда локальная переменная или параметр функции затеняет член класса:

class Foo {
  int i;

  Foo* f() {
    return this; // return the 'this' pointer
  }
  void g(){
    j(this); // pass the 'this' pointer to some function j
  }
  void h(int i) {
    this->i = i; // need to distinguish between class member 'i' and function parameter 'i'
  }
};

Два первых случая (f() и g()) являются наиболее значимыми. Третьего можно избежать, просто переименовав переменную-член класса, но никак нельзя обойтись без использования this в первых двух случаях.

1
ответ дан 6 December 2019 в 04:50
поделиться

Другой возможный вариант использования этого:

#include <iostream>
using namespace std;

class A
{
    public:
    void foo()
    {
        cout << "foo() of A\n";
    }
};

class B : A
{
    public:
    void foo()
    {
        ((A *)this)->foo(); // Same as A::foo();
        cout << "foo() of B\n";
    }
};

int main()
{
    B b;
    b.foo();
    return 0;
}
g++ this.cpp -o this
./this 
foo() of A
foo() of B
1
ответ дан 6 December 2019 в 04:50
поделиться

Еще одно использование this - предотвращение сбоев, если метод вызывается для метода, вызываемого по NULL-указателю (аналогично шаблону объекта NULL):

class Foo 
{
public:
    void Fn() 
    {
        if (!this)
            return;
        ...
    }
};
...
void UseFoo(Foo* something)
{
    something->Fn(); // will not crash if Foo == NULL
}

Полезно это или нет, зависит от контекста, но я видел это время от времени и сам тоже использовал.

1
ответ дан 6 December 2019 в 04:50
поделиться

При передаче ссылки на объект в одном из его методов. Например:

struct Event
{
    EventProducer* source;
};

class SomeContrivedClass : public EventProducer
{
public:
   void CreateEvent()
   {
       Event event;
       event.source = this;
       EventManager.ProcessEvent(event);
   } 
};
3
ответ дан 6 December 2019 в 04:50
поделиться

Это полезно, если вам нужно передать указатель на текущий объект другой функции или вернуть его. Последний используется для объединения функций вместе:

Obj* Obj::addProperty(std::string str) {
    // do stuff
    return this;
}

obj->addProperty("foo")->addProperty("bar")->addProperty("baz");
9
ответ дан 6 December 2019 в 04:50
поделиться

Самостоятельное назначение защиты

0
ответ дан 6 December 2019 в 04:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: