[英]When should I make explicit use of the `this` pointer?
我什么時候應該在類的方法中明確寫this->member
?
通常,您不必這樣做, this->
是隱含的。
有時,存在名稱歧義,可用於消除類成員和局部變量的歧義。 但是,這是一個完全不同的情況,其中this->
是明確需要的。
考慮以下代碼:
template<class T>
struct A {
T i;
};
template<class T>
struct B : A<T> {
T foo() {
return this->i; //standard accepted by all compilers
//return i; //clang and gcc will fail
//clang 13.1.6: use of undeclared identifier 'i'
//gcc 11.3.0: 'i' was not declared in this scope
//Microsoft C++ Compiler 2019 will accept it
}
};
int main() {
B<int> b;
b.foo();
}
如果省略this->
,一些編譯器不知道如何處理i
。 為了告訴它i
確實是A<T>
的成員,對於任何T
,都需要this->
前綴。
注意:仍然可以使用以下方法省略this->
前綴:
template<class T>
struct B : A<T> {
int foo() {
return A<T>::i; // explicitly refer to a variable in the base class
//where 'i' is now known to exist
}
};
如果在方法中聲明一個與現有成員同名的局部變量,則必須使用 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
指針有幾個原因。
雖然我通常不特別喜歡它,但我看到其他人使用它-> 只是為了從智能感知中獲得幫助!
在少數情況下必須使用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)可用的替代方案:作為編碼風格的一部分,記錄哪些變量是成員變量而不是局部變量。 我更喜歡不同的命名方案,其中成員變量永遠不能與本地人具有相同的名稱。 目前,我將mName
用於成員, name
用於本地人。
一些編碼標准使用方法 (2),因為他們聲稱它使代碼更易於閱讀。
例子:
假設 MyClass 有一個名為 'count' 的成員變量
void MyClass::DoSomeStuff(void)
{
int count = 0;
.....
count++;
this->count = count;
}
另一種情況是調用運算符時。 例如,而不是
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)
但這似乎很常見。
如果你在兩個潛在的命名空間中有一個同名的符號,你只需要使用 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->”。
這個的其他用途(正如我在閱讀摘要和一半問題時所想的那樣......),忽略其他答案中的(壞)命名歧義,如果你想轉換當前對象,將它綁定在一個函數對象中或將其與指向成員的指針一起使用。
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;
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
指針的主要(或者我可以說是唯一的)目的是它指向用於調用成員函數的對象。
基於這個目的,我們可以有一些情況,只有使用this
指針才能解決問題。
例如,我們必須在成員函數中返回調用對象,參數是同一個類對象:
class human {
...
human & human::compare(human & h){
if (condition)
return h; // argument object
else
return *this; // invoking object
}
};
您需要使用this
來消除參數/局部變量和成員變量之間的歧義。
class Foo
{
protected:
int myX;
public:
Foo(int myX)
{
this->myX = myX;
}
};
我在 Effective C++ 書中發現了另一個顯式使用“this”指針的有趣案例。
例如,假設您有一個 const 函數,例如
unsigned String::length() const
您不想為每個調用計算字符串的長度,因此您想緩存它做類似的事情
unsigned String::length() const
{
if(!lengthInitialized)
{
length = strlen(data);
lengthInitialized = 1;
}
}
但這不會編譯 - 您正在更改 const 函數中的對象。
解決這個問題的技巧需要將this轉換為非常量this :
String* const nonConstThis = (String* const) this;
然后,你就可以在上面做
nonConstThis->lengthInitialized = 1;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.