我啥时候应该明确使用 `this` 指针?

Posted

技术标签:

【中文标题】我啥时候应该明确使用 `this` 指针?【英文标题】:When should I make explicit use of the `this` pointer?我什么时候应该明确使用 `this` 指针? 【发布时间】:2010-11-02 20:41:43 【问题描述】:

我什么时候应该明确写this->member 上课?

【问题讨论】:

我确定这是一个骗子,但它当然是不可搜索的。不是第一次,我希望 this 指针被称为 self! 不仅如此,我希望它是一个参考。 相同。 :|顺便说一下,原因如下:research.att.com/~bs/bs_faq2.html#this 如果对方不知道答案,这个方法显然是行不通的。 @JohnH.: 嗯,看起来research.att.com/~bs/ 现在是stroustrup.com。新链接:stroustrup.com/bs_faq2.html#this 【参考方案1】:

通常,您不必这样做,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-&gt;,编译器不知道如何处理i,因为它可能存在于A 的所有实例中,也可能不存在。为了告诉它i 确实是A&lt;T&gt; 的成员,对于任何T,都需要this-&gt; 前缀。

注意:仍然可以通过以下方式省略 this-&gt; 前缀:

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 中。我可以举个例子吗? @CamJackson 我在 Visual Studio 上尝试了代码。无论“this->”是否存在,结果都是一样的。有什么想法吗? @CamJackson:可以针对类型专门化课程:template&lt;&gt; struct A&lt;float&gt; float x; ;【参考方案2】:

如果在方法中声明一个与现有成员同名的局部变量,则必须使用 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

【讨论】:

我最好用 cout 我宁愿避免名称与“​​m_a”或“a_”等约定冲突。【参考方案3】:

您可能需要显式使用this 指针的原因有多种。

当您想将对对象的引用传递给某个函数时。 当存在与成员对象同名的本地声明对象时。 当您尝试访问 dependent base classes 的成员时。 有些人更喜欢这种表示法,以便在他们的代码中直观地消除成员访问的歧义。

【讨论】:

【参考方案4】:

虽然我通常不特别喜欢它,但我看到其他人使用它-> 只是为了从智能感知中获得帮助!

【讨论】:

【参考方案5】:

在少数情况下必须使用this,而在其他情况下使用this 指针是解决问题的一种方法。

1) 可用的替代方案:要解决局部变量和类成员之间的歧义,as illustrated by @ASk。

2) 别无选择:从成员函数返回指向this 的指针或引用。在重载operator+operator-operator= 等时经常这样做(并且应该这样做):

class Foo

  Foo& operator=(const Foo& rhs)
  
    return * this;
  
;

这样做允许使用称为“method chaining”的习惯用法,您可以在一行代码中对一个对象执行多项操作。如:

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

【讨论】:

对于第 3 点,当您说“不替代”时,实际上还有其他几种方法:1)int ret = 6 * VahHolder&lt;Val&gt;::GetVal(); 或 2)在类中(不是函数)using ValHolder&lt;Val&gt;::GetVal; 也进行不合格查找为 GetVal 工作,即使在依赖的上下文中。 godbolt.org/z/n5PY3j51c【参考方案6】:
    成员变量将被隐藏的位置 局部变量 如果你只想 明确表示你 正在调用实例方法/变量

一些编码标准使用方法 (2),因为他们声称它使代码更易于阅读。

示例: 假设 MyClass 有一个名为 'count' 的成员变量

void MyClass::DoSomeStuff(void)

   int count = 0;

   .....
   count++;
   this->count = count;

【讨论】:

【参考方案7】:

另一种情况是调用运算符时。例如。而不是

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-&gt;swap(Type(rhs));【参考方案8】:

只有在两个潜在命名空间中有同名符号时,才需要使用 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-&gt; 的一种用法,很容易避免(只需给局部变量一个不同的名称)。这个答案甚至没有提到this 的所有真正有趣的用途。【参考方案9】:

这个的其他用途(正如我在阅读摘要和一半问题时所想的那样......),忽略其他答案中的(坏)命名消歧,如果你想转换当前对象,请将其绑定到函数对象或将其与指向成员的指针一起使用。

演员表

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 的其他用途,而不仅仅是 this->member。

【讨论】:

【参考方案10】:

您需要使用this 来消除参数/局部变量和成员变量之间的歧义。

class Foo

protected:
  int myX;

public:
  Foo(int myX)
  
    this->myX = myX; 
  
;

【讨论】:

不,你不需要它,你可以使用它。您还可以为函数参数使用不同的名称,这样做的好处是没有两个实体具有相同的名称。【参考方案11】:

this 指针的主要(或者我可以说是唯一的)目的是它指向用于调用成员函数的对象。

基于这个目的,我们可以有一些情况,只有使用this指针才能解决问题。

例如,我们必须在成员函数中返回调用对象,参数是同一个类对象:

class human 

... 

human & human::compare(human & h)
    if (condition)
        return h;       // argument object
    else 
        return *this;   // invoking object
    
;

【讨论】:

【参考方案12】:

我在 Effective C++ 一书中发现了另一个显式使用“this”指针的有趣案例。

例如,假设您有一个类似的 const 函数

  unsigned String::length() const

你不想为每个调用计算字符串的长度,因此你想缓存它做类似的事情

  unsigned String::length() const
  
    if(!lengthInitialized)
    
      length = strlen(data);
      lengthInitialized = 1;
    
  

但这不会编译 - 您正在更改 const 函数中的对象。

解决这个问题的技巧需要将 this 转换为非 const this

  String* const nonConstThis = (String* const) this;

那么,你就可以在上面做

  nonConstThis->lengthInitialized = 1;

【讨论】:

或者您可以使length 可变,甚至将其放入嵌套结构中。抛弃 constness 几乎从来都不是一个好主意。 请不要。如果要从const 成员函数更改成员,它应该是mutable。否则你会让其他维护者的生活变得更加复杂。

以上是关于我啥时候应该明确使用 `this` 指针?的主要内容,如果未能解决你的问题,请参考以下文章

我啥时候应该传递“T* const&”类型的指针?

我啥时候想从原始指针构造一个共享指针

我啥时候应该使用 FutureBuilder?

我啥时候应该使用 QThread::HighestPriority

Firebase:我啥时候应该使用 refreshToken?

我啥时候应该使用“while 循环”?