Иногда возникает двусмысленность имени, где его можно использовать для устранения неоднозначности членов класса и локальных переменных. Однако здесь совершенно другой случай, когда this->это явно требуется.
Если вы опустите его this->, компилятор не знает, что делать i, поскольку он может существовать или не существовать во всех экземплярах A. Чтобы сказать, что iон действительно является членом A<T>любого T, this->требуется префикс.
Примечание: можно по-прежнему опустить this->префикс, используя:
template<classT>
structB : A<T> {
using A<T>::i; // explicitly refer to a variable in the base classintfoo(){
return i; // i is now known to exist
}
};
Это особенно неприятный случай. Меня это уже кусало.
Джейсон Бейкер,
5
Это может быть глупый вопрос, но я не понимаю, почему iможет не существовать в A. Могу я привести пример?
Кэм Джексон
1
@CamJackson Я пробовал код в Visual Studio. результаты будут одинаковыми независимо от того, существует "this->" или нет. Любая идея?
Peng Zhang
8
@CamJackson: Можно специализировать классы по типу:template<> struct A<float> { float x; };
Macke
31
Если вы объявляете локальную переменную в методе с тем же именем, что и существующий член, вам придется использовать this-> var для доступа к члену класса вместо локальной переменной.
#include<iostream>usingnamespacestd;
classA
{public:
int a;
voidf(){
a = 4;
int a = 5;
cout << a << endl;
cout << this->a << endl;
}
};
intmain(){
A a;
a.f();
}
Есть несколько случаев, когда thisнеобходимо использовать using , а есть другие, где использование thisуказателя является одним из способов решения проблемы.
1) Доступные альтернативы : для устранения неоднозначности между локальными переменными и членами класса, как показано @ASk .
2) Нет альтернативы: вернуть указатель или ссылку на thisфункцию-член. Это часто делается (и должно быть сделано) при перегрузке operator+, operator-, operator=и т.д.:
Это позволяет использовать идиому, известную как « цепочка методов », при которой вы выполняете несколько операций с объектом в одной строке кода. Такие как:
Одни считают это консенсусом, другие - мерзостью. Считайте меня в последнюю группу.
3) Нет альтернативы: разрешить имена в зависимых типах. Это происходит при использовании шаблонов, как в этом примере:
#include<iostream>template <typename Val>
classValHolder
{private:
Val mVal;
public:
ValHolder (const Val& val)
:
mVal (val)
{
}
Val& GetVal(){ return mVal; }
};
template <typename Val>
classValProcessor
: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;
}
};
intmain(){
ValProcessor <int> proc (42);
constint val = proc.ComputeValue();
std::cout << val << "\n";
}
4) Доступные альтернативы: как часть стиля кодирования, чтобы задокументировать, какие переменные являются переменными-членами, а не локальными. Я предпочитаю другую схему именования, в которой переменные-члены никогда не могут иметь то же имя, что и локальные. В настоящее время я использую mNameдля членов и nameдля местных жителей.
В своем последнем случае, обратите внимание , что вы можете вызвать не- constфункцию члена на временном ( Type(rhs).swap(*this);законно и правильно) , но временно не может связываться с неконстантным опорным параметром (компилятор брака swap(Type(rhs));, а также this->swap(Type(rhs));)
Бен Фойет
4
Вам нужно использовать this-> только в том случае, если у вас есть символ с тем же именем в двух потенциальных пространствах имен. Например:
classA {public:
voidsetMyVar(int);
voiddoStuff();
private:
int myVar;
}
voidA::setMyVar(int myVar){
this->myVar = myVar; // <- Interesting point in the code
}
voidA::doStuff(){
int myVar = ::calculateSomething();
this->myVar = myVar; // <- Interesting point in the code
}
В интересных местах кода ссылка на myVar будет ссылаться на локальную (параметр или переменную) myVar. Чтобы получить доступ к члену класса, также называемому myVar, вам необходимо явно использовать this->.
Это единственное использование this->, которого следует избегать (просто дайте локальной переменной другое имя). В thisэтом ответе даже не упоминаются все действительно интересные варианты использования .
cmaster - восстановить Монику
4
Другие варианты использования для этого (как я думал, когда я прочитал резюме и половину вопроса ....), Игнорируя (плохое) неоднозначность имен в других ответах, - это если вы хотите использовать текущий объект, привяжите его к объекту функции или используйте его с указателем на член.
Броски
voidFoo::bar(){
misc_nonconst_stuff();
const Foo* const_this = this;
const_this->bar(); // calls const versiondynamic_cast<Bar*>(this)->bar(); // calls specific virtual function in case of multi-inheritance
}
voidFoo::bar()const{}
Нет, тебе это не нужно , можешь пользоваться . Вы также можете использовать другое имя для аргумента функции, что имеет то преимущество, что у него нет двух сущностей с одинаковым именем.
cmaster - восстановить монику
3
Основное (или, можно сказать, единственное) назначение thisуказателя состоит в том, что он указывает на объект, используемый для вызова функции-члена.
Исходя из этого, мы можем иметь некоторые случаи, когда только использование thisуказателя может решить проблему.
Например, мы должны вернуть вызывающий объект в функции-члене с аргументом того же объекта класса:
Или вы можете сделать lengthизменяемым или даже поместить его во вложенную структуру. Отказ от константности почти никогда не бывает хорошей идеей.
Ричард Дж. Росс III
3
Пожалуйста, не надо. Если член должен быть изменен из constфункций-членов, он должен быть mutable. В противном случае вы усложняете жизнь себе и другим сопровождающим.
research.att.com/~bs/
сейчасstroustrup.com
. Новая ссылка: stroustrup.com/bs_faq2.html#thisОтветы:
Обычно это не обязательно
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 } };
источник
i
может не существовать вA
. Могу я привести пример?template<> struct A<float> { float x; };
Если вы объявляете локальную переменную в методе с тем же именем, что и существующий член, вам придется использовать 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
источник
Есть несколько причин, по которым вам может потребоваться
this
явное использование указателя.источник
Хотя обычно мне это не особо нравится, я видел, как другие использовали это-> просто, чтобы получить помощь от intellisense!
источник
Некоторые стандарты кодирования используют подход (2), поскольку они утверждают, что он упрощает чтение кода.
Пример:
предположим, что MyClass имеет переменную-член с именем count
void MyClass::DoSomeStuff(void) { int count = 0; ..... count++; this->count = count; }
источник
Есть несколько случаев, когда
this
необходимо использовать using , а есть другие, где использование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) Доступные альтернативы: как часть стиля кодирования, чтобы задокументировать, какие переменные являются переменными-членами, а не локальными. Я предпочитаю другую схему именования, в которой переменные-члены никогда не могут иметь то же имя, что и локальные. В настоящее время я использую
mName
для членов иname
для местных жителей.источник
Еще один случай - вызов операторов. Например, вместо
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)
но это, кажется, обычное дело.источник
const
функцию члена на временном (Type(rhs).swap(*this);
законно и правильно) , но временно не может связываться с неконстантным опорным параметром (компилятор бракаswap(Type(rhs));
, а такжеthis->swap(Type(rhs));
)Вам нужно использовать this-> только в том случае, если у вас есть символ с тем же именем в двух потенциальных пространствах имен. Например:
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->.
источник
this->
, которого следует избегать (просто дайте локальной переменной другое имя). Вthis
этом ответе даже не упоминаются все действительно интересные варианты использования .Другие варианты использования для этого (как я думал, когда я прочитал резюме и половину вопроса ....), Игнорируя (плохое) неоднозначность имен в других ответах, - это если вы хотите использовать текущий объект, привяжите его к объекту функции или используйте его с указателем на член.
Броски
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 {}
Привязка
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-to-member
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)(); } }
Надеюсь, это поможет показать другие способы использования этого, кроме this-> member.
источник
Вам нужно использовать
this
для устранения неоднозначности между параметрами / локальными переменными и переменными-членами.class Foo { protected: int myX; public: Foo(int myX) { this->myX = myX; } };
источник
Основное (или, можно сказать, единственное) назначение
this
указателя состоит в том, что он указывает на объект, используемый для вызова функции-члена.Исходя из этого, мы можем иметь некоторые случаи, когда только использование
this
указателя может решить проблему.Например, мы должны вернуть вызывающий объект в функции-члене с аргументом того же объекта класса:
class human { ... human & human::compare(human & h){ if (condition) return h; // argument object else return *this; // invoking object } };
источник
Еще один интересный случай явного использования указателя this я нашел в книге «Эффективный C ++».
Например, скажем, у вас есть константная функция вроде
unsigned String::length() const
Вы не хотите рассчитывать длину строки для каждого вызова, поэтому вы хотите кэшировать ее, выполняя что-то вроде
unsigned String::length() const { if(!lengthInitialized) { length = strlen(data); lengthInitialized = 1; } }
Но это не скомпилируется - вы меняете объект в константной функции.
Чтобы решить эту проблему, нужно преобразовать this в неконстантный this :
String* const nonConstThis = (String* const) this;
Затем вы сможете сделать это
nonConstThis->lengthInitialized = 1;
источник
length
изменяемым или даже поместить его во вложенную структуру. Отказ от константности почти никогда не бывает хорошей идеей.const
функций-членов, он должен бытьmutable
. В противном случае вы усложняете жизнь себе и другим сопровождающим.