我啥时候应该明确使用 `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->
,编译器不知道如何处理i
,因为它可能存在于A
的所有实例中,也可能不存在。为了告诉它i
确实是A<T>
的成员,对于任何T
,都需要this->
前缀。
注意:仍然可以通过以下方式省略 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
;
【讨论】:
使用声明很好用:) 这是一个特别讨厌的案例。我以前被它咬过。 这可能是一个愚蠢的问题,但我不明白为什么i
可能不存在于A
中。我可以举个例子吗?
@CamJackson 我在 Visual Studio 上尝试了代码。无论“this->”是否存在,结果都是一样的。有什么想法吗?
@CamJackson:可以针对类型专门化课程:template<> struct A<float> 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
指针的原因有多种。
【讨论】:
【参考方案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<Val>::GetVal();
或 2)在类中(不是函数)using ValHolder<Val>::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->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->
的一种用法,很容易避免(只需给局部变量一个不同的名称)。这个答案甚至没有提到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` 指针?的主要内容,如果未能解决你的问题,请参考以下文章
我啥时候应该使用 QThread::HighestPriority