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

方法中显式编写 this->member的时间 上课?

45958 次浏览

If you declare a local variable in a method with the same name as an existing member, you will have to use this->var to access the class member instead of the local variable.

#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来消除参数/局部变量和成员变量之间的歧义。

class Foo
{
protected:
int myX;


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

只有在两个可能的名称空间中有一个具有相同名称的符号时,才必须使用 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->

考虑以下代码:

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
}


};
  1. 隐藏成员变量的位置 局部变量
  2. 如果你只是想 明确表示 正在调用一个实例方法/变量


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

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

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


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

可能需要显式使用 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-to-member

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-> 成员之外的其他用途。

另一种情况是调用运算符

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”指针在有效的 C + + 书中。

例如,假设您有一个常量函数,如

  unsigned String::length() const

您不希望为每个调用计算 String 的长度,因此需要像下面这样缓存它

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

但是这不会被编译-你在一个 const 函数中改变了对象。

要解决这个问题,需要将 这个转换为非常量 这个:

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

然后,你就可以在上面做

  nonConstThis->lengthInitialized = 1;

虽然我通常并不特别喜欢它,但是我看到其他人使用这个-> 仅仅是为了从智慧中获得帮助!

使用 this 必须的的情况很少,而使用 this指针是解决问题的一种方法。

1) 可供选择: 为了解决局部变量和类成员之间的模糊性,如@ASK 所示

从成员函数返回指向 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

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

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

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

class human {


...


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