Czasami występuje niejednoznaczność nazwy, w której można ją wykorzystać do ujednoznacznienia członków klasy i zmiennych lokalnych. Jednak tutaj jest zupełnie inny przypadek, w którym this->jest to wyraźnie wymagane.
Jeśli pominiesz this->, kompilator nie będzie wiedział, jak traktować i, ponieważ może istnieć lub nie we wszystkich wystąpieniach A. Aby stwierdzić, że ijest członkiem A<T>, dla każdego T, this->wymagany jest przedrostek.
Uwaga: nadal można pominąć this->prefiks, używając:
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
}
};
To szczególnie nieprzyjemny przypadek. Już wcześniej mnie to ugryzło.
Jason Baker
5
To może być głupie pytanie, ale nie rozumiem, dlaczego imoże nie istnieć w A. Czy mógłbym dostać przykład?
Cam Jackson,
1
@CamJackson Wypróbowałem kod w Visual Studio. wyniki są takie same, niezależnie od tego, czy „to->” istniało, czy nie. Dowolny pomysł?
Peng Zhang
8
@CamJackson: Można specjalizować się w zajęciach typu:template<> struct A<float> { float x; };
Macke,
31
Jeśli deklarujesz zmienną lokalną w metodzie o tej samej nazwie, co istniejący element członkowski, będziesz musiał użyć this-> var, aby uzyskać dostęp do elementu członkowskiego klasy zamiast do zmiennej lokalnej.
#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();
}
Jest kilka przypadków, w których thisnależy użyć using , a są inne, w których użycie thiswskaźnika jest jednym ze sposobów rozwiązania problemu.
1) Dostępne alternatywy : Aby rozwiązać niejednoznaczność między zmiennymi lokalnymi a składowymi klas, jak pokazano na @ASk .
2) Brak alternatywy: aby zwrócić wskaźnik lub odwołanie do thisfunkcji składowej. Jest to często zrobić (i powinno być zrobione) przy przeciążeniu operator+, operator-, operator=itp:
Niektórzy uważają ten błąd, inni uważają to za obrzydliwość. Zalicz mnie do tej drugiej grupy.
3) Brak alternatywy: rozwiązywanie nazw w typach zależnych. Pojawia się podczas korzystania z szablonów, jak w tym przykładzie:
#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) Dostępne alternatywy: jako część stylu kodowania, do udokumentowania, które zmienne są zmiennymi składowymi, a które zmiennymi lokalnymi. Wolę inny schemat nazewnictwa, w którym zmienne składowe nigdy nie mogą mieć takiej samej nazwy jak lokalni. Obecnie używam mNamedla członków i namedla mieszkańców.
W ostatnim przypadku należy pamiętać, że można zadzwonić niebędącą constfunkcji członka na tymczasowy ( Type(rhs).swap(*this);jest legalne i zgodne z prawdą), ale przejściowych nie wiążą się z const parametru odniesienia (odrzuty kompilatora swap(Type(rhs));, jak również this->swap(Type(rhs));)
Ben Voigt
4
Musisz użyć this-> tylko wtedy, gdy masz symbol o tej samej nazwie w dwóch potencjalnych przestrzeniach nazw. Weź na przykład:
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
}
W interesujących punktach kodu odwołanie do myVar będzie odnosić się do lokalnego (parametru lub zmiennej) myVar. Aby uzyskać dostęp do elementu klasy zwanego również myVar, musisz jawnie użyć „this->”.
Jest to jedyne zastosowanie, this->którego należy unikać (wystarczy nadać zmiennej lokalnej inną nazwę). thisTa odpowiedź nie wspomina nawet o wszystkich naprawdę interesujących zastosowaniach .
cmaster
4
Inne zastosowania do tego (jak myślałem, kiedy czytałem podsumowanie i połowę pytania ....), Pomijając (złe) ujednoznacznienie nazewnictwa w innych odpowiedziach, to jeśli chcesz rzutować bieżący obiekt, powiązaj go w obiekcie funkcji lub użyj go ze wskaźnikiem do elementu członkowskiego.
Rzuty
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{}
Nie, nie potrzebujesz tego, możesz go użyć . Możesz również użyć innej nazwy dla argumentu funkcji, co ma tę zaletę, że nie ma dwóch jednostek o tej samej nazwie.
cmaster
3
Głównym (lub mogę powiedzieć, jedynym) celem thiswskaźnika jest wskazanie obiektu używanego do wywołania funkcji składowej.
Bazując na tym celu, możemy mieć przypadki, w których tylko użycie thiswskaźnika może rozwiązać problem.
Na przykład, musimy zwrócić obiekt wywołujący w funkcji składowej, której argument jest tym samym obiektem klasy:
Lub możesz uczynić lengthmutable, a nawet umieścić go w zagnieżdżonej strukturze. Rzucanie konsternacji prawie nigdy nie jest dobrym pomysłem.
Richard J. Ross III
3
Proszę nie. Jeśli element członkowski ma zostać zmieniony z constfunkcji składowych, powinien być mutable. W przeciwnym razie utrudnisz życie sobie i innym opiekunom.
research.att.com/~bs/
to , że jest terazstroustrup.com
. Nowy link: stroustrup.com/bs_faq2.html#thisOdpowiedzi:
Zwykle nie musisz tego robić
this->
.Czasami występuje niejednoznaczność nazwy, w której można ją wykorzystać do ujednoznacznienia członków klasy i zmiennych lokalnych. Jednak tutaj jest zupełnie inny przypadek, w którym
this->
jest to wyraźnie wymagane.Rozważ następujący kod:
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(); }
Jeśli pominiesz
this->
, kompilator nie będzie wiedział, jak traktowaći
, ponieważ może istnieć lub nie we wszystkich wystąpieniachA
. Aby stwierdzić, żei
jest członkiemA<T>
, dla każdegoT
,this->
wymagany jest przedrostek.Uwaga: nadal można pominąć
this->
prefiks, używając: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 } };
źródło
i
może nie istnieć wA
. Czy mógłbym dostać przykład?template<> struct A<float> { float x; };
Jeśli deklarujesz zmienną lokalną w metodzie o tej samej nazwie, co istniejący element członkowski, będziesz musiał użyć this-> var, aby uzyskać dostęp do elementu członkowskiego klasy zamiast do zmiennej lokalnej.
#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(); }
wydruki:
5
4
źródło
Istnieje kilka powodów, dla których może być konieczne
this
jawne użycie wskaźnika.źródło
Chociaż zwykle mi się to nie podoba, widziałem, jak inni używają tego -> po prostu do uzyskania pomocy od inteligencji!
źródło
Niektóre standardy kodowania używają podejścia (2), ponieważ twierdzą, że ułatwia to odczytanie kodu.
Przykład:
Załóżmy, że MyClass ma zmienną składową o nazwie „count”
void MyClass::DoSomeStuff(void) { int count = 0; ..... count++; this->count = count; }
źródło
Jest kilka przypadków, w których
this
należy użyć using , a są inne, w których użyciethis
wskaźnika jest jednym ze sposobów rozwiązania problemu.1) Dostępne alternatywy : Aby rozwiązać niejednoznaczność między zmiennymi lokalnymi a składowymi klas, jak pokazano na @ASk .
2) Brak alternatywy: aby zwrócić wskaźnik lub odwołanie do
this
funkcji składowej. Jest to często zrobić (i powinno być zrobione) przy przeciążeniuoperator+
,operator-
,operator=
itp:class Foo { Foo& operator=(const Foo& rhs) { return * this; } };
W ten sposób można zastosować idiom zwany „ łączeniem metod ”, w którym wykonujesz kilka operacji na obiekcie w jednej linii kodu. Jak na przykład:
Student st; st.SetAge (21).SetGender (male).SetClass ("C++ 101");
Niektórzy uważają ten błąd, inni uważają to za obrzydliwość. Zalicz mnie do tej drugiej grupy.
3) Brak alternatywy: rozwiązywanie nazw w typach zależnych. Pojawia się podczas korzystania z szablonów, jak w tym przykładzie:
#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) Dostępne alternatywy: jako część stylu kodowania, do udokumentowania, które zmienne są zmiennymi składowymi, a które zmiennymi lokalnymi. Wolę inny schemat nazewnictwa, w którym zmienne składowe nigdy nie mogą mieć takiej samej nazwy jak lokalni. Obecnie używam
mName
dla członków iname
dla mieszkańców.źródło
Jeszcze jeden przypadek dotyczy wywoływania operatorów. Np. Zamiast
bool Type::operator!=(const Type& rhs) { return !operator==(rhs); }
możesz powiedzieć
bool Type::operator!=(const Type& rhs) { return !(*this == rhs); }
Które mogłoby być bardziej czytelne. Innym przykładem jest kopiuj i zamień:
Type& Type::operator=(const Type& rhs) { Type temp(rhs); temp.swap(*this); }
Nie wiem, dlaczego nie jest napisane,
swap(temp)
ale wydaje się, że jest to powszechne.źródło
const
funkcji członka na tymczasowy (Type(rhs).swap(*this);
jest legalne i zgodne z prawdą), ale przejściowych nie wiążą się z const parametru odniesienia (odrzuty kompilatoraswap(Type(rhs));
, jak równieżthis->swap(Type(rhs));
)Musisz użyć this-> tylko wtedy, gdy masz symbol o tej samej nazwie w dwóch potencjalnych przestrzeniach nazw. Weź na przykład:
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 }
W interesujących punktach kodu odwołanie do myVar będzie odnosić się do lokalnego (parametru lub zmiennej) myVar. Aby uzyskać dostęp do elementu klasy zwanego również myVar, musisz jawnie użyć „this->”.
źródło
this->
którego należy unikać (wystarczy nadać zmiennej lokalnej inną nazwę).this
Ta odpowiedź nie wspomina nawet o wszystkich naprawdę interesujących zastosowaniach .Inne zastosowania do tego (jak myślałem, kiedy czytałem podsumowanie i połowę pytania ....), Pomijając (złe) ujednoznacznienie nazewnictwa w innych odpowiedziach, to jeśli chcesz rzutować bieżący obiekt, powiązaj go w obiekcie funkcji lub użyj go ze wskaźnikiem do elementu członkowskiego.
Rzuty
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 {}
Wiążący
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)(); } }
Mam nadzieję, że pomoże to pokazać inne zastosowania tego niż tylko ten-> członek.
źródło
Musisz użyć,
this
aby rozróżnić parametry / zmienne lokalne i zmienne składowe.class Foo { protected: int myX; public: Foo(int myX) { this->myX = myX; } };
źródło
Głównym (lub mogę powiedzieć, jedynym) celem
this
wskaźnika jest wskazanie obiektu używanego do wywołania funkcji składowej.Bazując na tym celu, możemy mieć przypadki, w których tylko użycie
this
wskaźnika może rozwiązać problem.Na przykład, musimy zwrócić obiekt wywołujący w funkcji składowej, której argument jest tym samym obiektem klasy:
class human { ... human & human::compare(human & h){ if (condition) return h; // argument object else return *this; // invoking object } };
źródło
Znalazłem inny interesujący przypadek jawnego użycia wskaźnika „this” w książce Effective C ++.
Na przykład, powiedzmy, że masz funkcję const, taką jak
unsigned String::length() const
Nie chcesz obliczać długości łańcucha dla każdego wywołania, dlatego chcesz go buforować, robiąc coś takiego
unsigned String::length() const { if(!lengthInitialized) { length = strlen(data); lengthInitialized = 1; } }
Ale to się nie skompiluje - zmieniasz obiekt w funkcji const.
Sztuczka, aby rozwiązać ten problem, wymaga rzutowania tego na inny element niż const this :
String* const nonConstThis = (String* const) this;
Wtedy będziesz mógł zrobić to powyżej
nonConstThis->lengthInitialized = 1;
źródło
length
mutable, a nawet umieścić go w zagnieżdżonej strukturze. Rzucanie konsternacji prawie nigdy nie jest dobrym pomysłem.const
funkcji składowych, powinien byćmutable
. W przeciwnym razie utrudnisz życie sobie i innym opiekunom.