Wann soll ich explizit schreiben this->member
in einer Methode einer Klasse?
Wann sollte ich den `this`-Zeiger explizit verwenden?
Fragen
Normalerweise müssen Sie nicht, this->
ist impliziert.
Manchmal gibt es eine Namensmehrdeutigkeit, die verwendet werden kann, um Klassenmitglieder und lokale Variablen zu disambiguieren. Hier ist jedoch ein ganz anderer Fall, wo this->
ist ausdrücklich erforderlich.
Betrachten Sie den folgenden Code:
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();
}
Wenn Sie weglassen this->
weiß der Compiler nicht zu behandeln i
da es in allen Instanziierungen von vorhanden sein kann oder nicht A
. Um ihm das zu sagen i
ist tatsächlich Mitglied A<T>
für alle T
der this->
Präfix ist erforderlich.
Hinweis: Es ist möglich, noch wegzulassen this->
Präfix durch Verwendung von:
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
}
};
-
Nette Verwendung der Verwendungsdeklaration 🙂
– Faisal Vali
14. Juni 2009 um 18:42 Uhr
-
Dies ist ein besonders unangenehmer Fall. Ich bin schon mal davon gebissen worden.
– Jason Baker
14. Juni 2009 um 19:53 Uhr
-
Das ist vielleicht eine dumme Frage, aber ich verstehe nicht warum
i
möglicherweise nicht vorhanden inA
. Könnte ich ein Beispiel bekommen?– Cam Jackson
19. Dezember 2013 um 1:08 Uhr
-
@CamJackson Ich habe den Code in Visual Studio ausprobiert. Die Ergebnisse sind gleich, egal ob “this->” existiert oder nicht. Irgendeine Idee?
– Peng Zhang
12. Januar 2014 um 10:57 Uhr
-
@CamJackson: Man kann Klassen auf Typ spezialisieren:
template<> struct A<float> { float x; };
– Macke
3. Dezember 2014 um 7:33 Uhr
PaV
Wenn Sie eine lokale Variable in einer Methode mit demselben Namen wie ein vorhandenes Mitglied deklarieren, müssen Sie this->var verwenden, um auf das Klassenmitglied statt auf die lokale Variable zuzugreifen.
#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();
}
Drucke:
5
4
-
Ich würde besser cout << A::a << endl; stattdessen. ``this" ist in diesem Fall unwichtig.
– siddhant3s
15. Juni 2009 um 0:15 Uhr
-
Ich würde lieber nur den Namenskonflikt mit Konventionen wie “m_a” oder “a_” vermeiden.
– Tom
15. Juni 2009 um 5:28 Uhr
Es gibt mehrere Gründe, warum Sie möglicherweise verwenden müssen this
Zeiger explizit.
- Wenn Sie eine Referenz auf Ihr Objekt an eine Funktion übergeben möchten.
- Wenn ein lokal deklariertes Objekt mit demselben Namen wie das Mitgliedsobjekt vorhanden ist.
- Wenn Sie versuchen, auf Mitglieder von zuzugreifen abhängige Basisklassen.
- Einige Leute bevorzugen die Notation, um Member-Zugriffe in ihrem Code visuell zu disambiguieren.
Obwohl ich es normalerweise nicht besonders mag, habe ich gesehen, dass andere dies verwenden -> einfach um Hilfe von Intellisense zu erhalten!
John Dibling
Es gibt nur wenige Fälle, in denen verwendet wird this
Muss verwendet werden, und es gibt andere, bei denen die verwendet werden this
Zeiger ist eine Möglichkeit, ein Problem zu lösen.
1) Alternativen verfügbar: Zum Auflösen von Mehrdeutigkeiten zwischen lokalen Variablen und Klassenmitgliedern, wie durch @ASk veranschaulicht.
2) Keine Alternative: Um einen Zeiger oder eine Referenz auf zurückzugeben this
aus einer Mitgliedsfunktion. Dies wird häufig beim Überladen gemacht (und sollte gemacht werden). operator+
, operator-
, operator=
etc:
class Foo
{
Foo& operator=(const Foo& rhs)
{
return * this;
}
};
Dies ermöglicht eine Redewendung, die als “Methodenverkettung“, wo Sie mehrere Operationen an einem Objekt in einer Codezeile ausführen. Wie zum Beispiel:
Student st;
st.SetAge (21).SetGender (male).SetClass ("C++ 101");
Manche halten das für prägnant, andere für ein Gräuel. Zählen Sie mich zur letzteren Gruppe.
3) Keine Alternative: So lösen Sie Namen in abhängigen Typen auf. Dies tritt auf, wenn Vorlagen verwendet werden, wie in diesem Beispiel:
#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) Verfügbare Alternativen: Als Teil des Codierungsstils, um zu dokumentieren, welche Variablen Mitgliedsvariablen im Gegensatz zu lokalen Variablen sind. Ich bevorzuge ein anderes Namensschema, bei dem Member-Variablen niemals denselben Namen wie Locals haben können. Derzeit verwende ich mName
für Mitglieder u name
für Einheimische.
-
Für Punkt 3, wenn Sie “keine Alternative” sagen, gibt es tatsächlich ein paar andere Möglichkeiten: 1)
int ret = 6 * VahHolder<Val>::GetVal();
oder 2) in der Klasse (funktioniert nicht)using ValHolder<Val>::GetVal;
macht auch die uneingeschränkte Suche für GetVal möglich, sogar in einem abhängigen Kontext. godbolt.org/z/n5PY3j51c– Chris Uzdavinis
25. Februar um 13:47 Uhr
Zebrabox
- Wo eine Mitgliedsvariable durch eine lokale Variable ausgeblendet würde
- Wenn Sie nur ausdrücklich klarstellen möchten, dass Sie eine Instanzmethode / -variable aufrufen
Einige Codierungsstandards verwenden Ansatz (2), da sie behaupten, dass dies den Code leichter lesbar macht.
Beispiel:
Angenommen, MyClass hat eine Member-Variable namens “count”.
void MyClass::DoSomeStuff(void)
{
int count = 0;
.....
count++;
this->count = count;
}
-
Für Punkt 3, wenn Sie “keine Alternative” sagen, gibt es tatsächlich ein paar andere Möglichkeiten: 1)
int ret = 6 * VahHolder<Val>::GetVal();
oder 2) in der Klasse (funktioniert nicht)using ValHolder<Val>::GetVal;
macht auch die uneingeschränkte Suche für GetVal möglich, sogar in einem abhängigen Kontext. godbolt.org/z/n5PY3j51c– Chris Uzdavinis
25. Februar um 13:47 Uhr
rlbond
Ein weiterer Fall ist der Aufruf von Operatoren. ZB statt
bool Type::operator!=(const Type& rhs)
{
return !operator==(rhs);
}
Sie können sagen
bool Type::operator!=(const Type& rhs)
{
return !(*this == rhs);
}
Was vielleicht besser lesbar ist. Ein weiteres Beispiel ist das Copy-and-Swap:
Type& Type::operator=(const Type& rhs)
{
Type temp(rhs);
temp.swap(*this);
}
Ich weiß nicht, warum es nicht geschrieben wird swap(temp)
aber das scheint üblich zu sein.
-
Beachten Sie in Ihrem letzten Fall, dass Sie einen Nicht-
const
Mitgliedsfunktion auf einer temporären (Type(rhs).swap(*this);
ist legal und korrekt), aber ein Temporär kann nicht an einen nicht konstanten Referenzparameter gebunden werden (der Compiler lehnt abswap(Type(rhs));
ebenso gut wiethis->swap(Type(rhs));
)– Ben Voigt
18. März 2019 um 14:51 Uhr
Ich bin mir sicher, dass dies ein Dupe ist, aber es ist natürlich nicht durchsuchbar. Nicht zum ersten Mal wünschte ich, dieser Zeiger würde self heißen!
– anon
14. Juni 2009 um 18:11 Uhr
Nicht nur das, ich wünschte, es wäre eine Referenz.
– rlbond
14. Juni 2009 um 18:25 Uhr
Dasselbe. 😐 Hier übrigens der Grund: research.att.com/~bs/bs_faq2.html#this
– GManNickG
14. Juni 2009 um 18:26 Uhr
Diese Methode funktioniert offensichtlich nicht, wenn die Person die Antwort nicht kennt.
– Fragen
15. Juni 2009 um 16:10 Uhr
@JohnH.: Hm, sieht aus wie
research.att.com/~bs/
ist jetztstroustrup.com
. Neuer Link: stroustrup.com/bs_faq2.html#this– GManNickG
17. Juli 2016 um 19:29 Uhr