什么时候应该显式使用`this`指针?


97

什么时候应该显式地编写this->member类的方法?


16
我敢肯定这是一个骗子,但它当然是不可搜索的。我不是第一次,希望这个指针被称为self!

5
不仅如此,我希望它可以作为参考。
rlbond

2
相同。:| 顺便说一下,这就是原因:research.att.com/~bs/bs_faq2.html#this
GManNickG 2009年

11
如果此人不知道答案,则此方法显然不起作用。
ASk

3
@JohnH .:嗯,看起来像是research.att.com/~bs/现在stroustrup.com。新链接:stroustrup.com/bs_faq2.html#this
GManNickG '16

Answers:


118

通常,您不必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->,编译器将不知道如何处理i,因为在所有实例化中都可能存在或不存在它A。为了告诉它i确实是的成员A<T>,对于任何Tthis->前缀都是必需的。

注意:仍然可以this->使用以下命令省略前缀:

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
    }

};

8
很好地使用using声明:)
Faisal Vali

3
这是一个特别令人讨厌的情况。我以前被它咬过。
杰森·贝克

5
这可能是一个愚蠢的问题,但我不明白为什么它i可能不存在A。我可以举个例子吗?
凸轮杰克逊

1
@CamJackson我在Visual Studio上尝试了代码。无论是否存在“ this->”,结果都是相同的。任何想法?
张鹏

8
@CamJackson:一个人可以专门研究以下类型的课程:template<> struct A<float> { float x; };
Macke

31

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


1
我最好使用cout << A :: a << endl; 代替。``这”在这种情况下不重要。
siddhant3s

3
我宁愿避免名称与“​​ m_a”或“ a_”之类的约定发生冲突。
汤姆

19

有几个原因可能导致您需要this显式使用指针。

  • 当您要将对对象的引用传递给某个函数时。
  • 存在与成员对象同名的本地声明的对象。
  • 当您尝试访问依赖基类的成员时
  • 有些人更喜欢用这种符号在视觉上消除代码中的成员访问歧义。

7

尽管我通常并不特别喜欢它,但我已经看到其他人使用this->只是从intellisense获得帮助!


6
  1. 成员变量将被局部变量隐藏的地方
  2. 如果您只想明确表明您正在调用实例方法/变量


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

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

void MyClass::DoSomeStuff(void)
{
   int count = 0;

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

5

另一种情况是调用操作员时。例如代替

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);是合法的,正确的),但暂时不能绑定到一个非const引用参数(编译废品swap(Type(rhs));以及this->swap(Type(rhs));
奔福格特

5

在少数情况下this 必须使用using ,而在其他情况下则使用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当地人使用。


4

仅当在两个潜在的名称空间中具有相同名称的符号时,才需要使用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->避免琐碎的一种用法(只需给局部变量起一个不同的名字)。this这个答案甚至都没有提到的所有真正有趣的用途。
cmaster-恢复莫妮卡2014年

4

这样做的其他用途(正如我在阅读摘要和一半的问题...时所认为的那样),而无视(不好)在其他答案中命名歧义,是如果要转换当前对象,请将其绑定到函数对象中或与指向成员的指针一起使用。

演员表

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。


3

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

class Foo
{
protected:
  int myX;

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

2
不,您不需要它,可以使用它。您也可以为函数参数使用不同的名称,其优点是不会使两个实体具有相同的名称。
cmaster-恢复莫妮卡2014年

3

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

基于此目的,我们可以将某些情况下仅使用 this指针才能解决问题。

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

class human {

... 

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

2

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

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

  unsigned String::length() const

您不想为每个调用计算String的长度,因此想像这样将其缓存

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

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

窍门来解决,这需要铸造对一个非const

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

然后,您就可以在上面

  nonConstThis->lengthInitialized = 1;

3
或者,您可以使其length可变,甚至将其放在嵌套结构中。放弃constness几乎从来不是一个好主意。
理查德·罗斯三世

3
请不要。如果要从const成员函数更改成员,则应为mutable。否则,您将使其他维护者的生活变得更加复杂。
DavidRodríguez-dribeas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.