Вариант использования указателя this в C ++ - PullRequest
7 голосов
/ 23 июля 2010

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

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

#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();
}

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

Добавлена ​​

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

Ответы [ 14 ]

12 голосов
/ 23 июля 2010

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

12 голосов
/ 23 июля 2010

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

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

     return *this;
}
9 голосов
/ 23 июля 2010

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

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

obj->addProperty("foo")->addProperty("bar")->addProperty("baz");
3 голосов
/ 23 июля 2010

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

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

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> и реализует print, то будет вызываться этот последний переопределитель, тогда как если тот же класс получен из test2<print>, код будет вызывать 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 голосов
/ 23 июля 2010

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

struct Event
{
    EventProducer* source;
};

class SomeContrivedClass : public EventProducer
{
public:
   void CreateEvent()
   {
       Event event;
       event.source = this;
       EventManager.ProcessEvent(event);
   } 
};
3 голосов
/ 23 июля 2010

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

QButton *button = new QButton(this);
2 голосов
/ 23 июля 2010

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

1 голос
/ 23 июля 2010

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

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

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

1 голос
/ 23 июля 2010

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

#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 голос
/ 23 июля 2010

Иногда вам нужно обратиться к самому объекту "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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...