Когда я должен явно использовать указатель `this`? - PullRequest
82 голосов
/ 14 июня 2009

Когда я должен явно написать this->member в методе класс?

Ответы [ 12 ]

105 голосов
/ 14 июня 2009

Как правило, вам не нужно, this-> подразумевается.

Иногда существует неоднозначность имени, где его можно использовать для устранения неоднозначности членов класса и локальных переменных. Однако здесь совершенно другой случай, когда явно требуется this->.

Рассмотрим следующий код:

template<class T>
struct A {
   int i;
};

template<class T>
struct B : A<T> {

    int foo() {
        return this->i;
    }

};

int main() {
    B<int> b;
    b.foo();
}

Если вы опустите this->, компилятор не знает, как обрабатывать i, поскольку он может существовать или не существовать во всех случаях A. Чтобы сказать, что i действительно является членом A<T>, для любого T требуется префикс this->.

Примечание: можно по-прежнему пропускать префикс this->, используя:

template<class T>
struct B : A<T> {

    using A<T>::i; // explicitly refer to a variable in the base class

    int foo() {
        return i; // i is now known to exist
    }

};
30 голосов
/ 14 июня 2009

Если вы объявляете локальную переменную в методе с тем же именем, что и существующий член, вам придется использовать this-> var для доступа к члену класса вместо локальной переменной.

#include <iostream>
using namespace std;
class A
{
    public:
        int a;

        void f() {
            a = 4;
            int a = 5;
            cout << a << endl;
            cout << this->a << endl;
        }
};

int main()
{
    A a;
    a.f();
}

печать:

5
4

16 голосов
/ 14 июня 2009

Существует несколько причин, по которым вам может понадобиться явно использовать указатель this.

  • Когда вы хотите передать ссылку на ваш объект в какую-либо функцию.
  • Когда существует локально объявленный объект с тем же именем, что и объект-член.
  • Когда вы пытаетесь получить доступ к членам зависимых базовых классов .
  • Некоторые люди предпочитают, чтобы нотация визуально устраняла неоднозначность доступа членов в их коде.
6 голосов
/ 14 июня 2009
  1. Где переменная-член будет скрыта локальная переменная
  2. Если вы просто хотите ясно дать понять, что вы вызывают метод / переменную экземпляра


Некоторые стандарты кодирования используют подход (2), поскольку утверждают, что он облегчает чтение кода.

Пример:
Предположим, что MyClass имеет переменную-член 'count'

void MyClass::DoSomeStuff(void)
{
   int count = 0;

   .....
   count++;
   this->count = count;
}
5 голосов
/ 15 июня 2009

В некоторых случаях использование this необходимо , а в других случаях использование указателя this является одним из способов решения проблемы.

1) Доступные альтернативы : Чтобы устранить неоднозначность между локальными переменными и членами класса, , как показано @ ASk .

2) Нет Альтернатива: Для возврата указателя или ссылки на this из функции-члена. Это часто делается (и должно быть сделано) при перегрузке operator+, operator-, operator= и т. Д .:

class Foo
{
  Foo& operator=(const Foo& rhs)
  {
    return * this;
  }
};

Это позволяет использовать идиому, известную как « цепочка методов », где вы выполняете несколько операций над объектом в одной строке кода. Такие как:

Student st;
st.SetAge (21).SetGender (male).SetClass ("C++ 101");

Некоторые считают этот принцип, другие считают его мерзостью. Считай меня в последней группе.

3) Нет Альтернатива: Для разрешения имен в зависимых типах. Это появляется при использовании шаблонов, как в этом примере:

#include <iostream>


template <typename Val>
class ValHolder
{
private:
  Val mVal;
public:
  ValHolder (const Val& val)
  :
    mVal (val)
  {
  }
  Val& GetVal() { return mVal; }
};

template <typename Val>
class ValProcessor
:
  public ValHolder <Val>
{
public:
  ValProcessor (const Val& val)
  :
    ValHolder <Val> (val)
  {
  }

  Val ComputeValue()
  {
//    int ret = 2 * GetVal();  // ERROR:  No member 'GetVal'
    int ret = 4 * this->GetVal();  // OK -- this tells compiler to examine dependant type (ValHolder)
    return ret;
  }
};

int main()
{
  ValProcessor <int> proc (42);
  const int val = proc.ComputeValue();
  std::cout << val << "\n";
}

4) Доступные альтернативы: Как часть стиля кодирования, документировать, какие переменные являются переменными-членами, а не локальными. Я предпочитаю другую схему именования, где у членов varibales никогда не может быть того же имени, что и у местных. В настоящее время я использую mName для членов и name для местных жителей.

5 голосов
/ 15 июня 2009

Хотя мне обычно это не особо нравится, я видел, как другие используют это -> просто чтобы получить помощь от intellisense!

5 голосов
/ 14 июня 2009

Еще один случай - при вызове операторов. Например. вместо

bool Type::operator!=(const Type& rhs)
{
    return !operator==(rhs);
}

Вы можете сказать

bool Type::operator!=(const Type& rhs)
{
    return !(*this == rhs);
}

Что может быть более читабельным. Другой пример - копирование и обмен:

Type& Type::operator=(const Type& rhs)
{
    Type temp(rhs);
    temp.swap(*this);
}

Я не знаю, почему не написано swap(temp), но это, кажется, распространено.

4 голосов
/ 14 июня 2009

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

Слепки

void Foo::bar() {
    misc_nonconst_stuff();
    const Foo* const_this = this;
    const_this->bar(); // calls const version

    dynamic_cast<Bar*>(this)->bar(); // calls specific virtual function in case of multi-inheritance
} 

void Foo::bar() const {}

Binding

void Foo::baz() {
     for_each(m_stuff.begin(), m_stuff.end(),  bind(&Foo:framboozle, this, _1));        
     for_each(m_stuff.begin(), m_stuff.end(), [this](StuffUnit& s) { framboozle(s); });         
} 

void Foo::framboozle(StuffUnit& su) {}

std::vector<StuffUnit> m_stuff;

PTR-на-член

void Foo::boz() {
    bez(&Foo::bar);
    bez(&Foo::baz);
} 

void Foo::bez(void (Foo::*func_ptr)()) {
    for (int i=0; i<3; ++i) {
        (this->*func_ptr)();
    }
}

Надеюсь, это поможет показать другое использование этого, кроме этого-> member.

4 голосов
/ 14 июня 2009

Вы должны использовать это-> только если у вас есть символ с тем же именем в двух потенциальных пространствах имен. Возьмем для примера:

class A {
public:
   void setMyVar(int);
   void doStuff();

private:
   int myVar;
}

void A::setMyVar(int myVar)
{
  this->myVar = myVar;  // <- Interesting point in the code
}

void A::doStuff()
{
  int myVar = ::calculateSomething();
  this->myVar = myVar; // <- Interesting point in the code
}

В интересных местах кода ссылка на myVar будет ссылаться на локальный (параметр или переменная) myVar. Для доступа к члену класса, также называемому myVar, вам нужно явно использовать «this ->».

3 голосов
/ 14 июня 2009

Вам необходимо использовать this для устранения неоднозначности между параметрами / локальными переменными и переменными-членами.

class Foo
{
protected:
  int myX;

public:
  Foo(int myX)
  {
    this->myX = myX; 
  }
};
...