簡體   English   中英

我什么時候應該明確使用 `this` 指針?

[英]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用於本地人。

  1. 成員變量將被局部變量隱藏的位置
  2. 如果您只想明確說明您正在調用實例方法/變量


一些編碼標准使用方法 (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;

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)();
    }
}

希望它有助於展示 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM