何时应该明确使用`this`指针?
什么时候应该在类的方法中明确地写this->member
?
通常情况下,你不必这样做,这是隐含的。
有时,名称不明确,它可以用来消除类成员和局部variables的歧义。 然而,这是一个完全不同的情况,这是明确要求的。
考虑下面的代码:
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 } };
如果在与现有成员具有相同名称的方法中声明局部variables,则必须使用this-> var来访问类成员,而不是本地variables。
#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; af(); }
打印:
五
4
有几个原因可能需要明确使用this
指针。
- 当你想传递你的对象的引用到一些函数。
- 当存在与成员对象具有相同名称的本地声明对象时。
- 当您尝试访问从属基类的成员时。
- 有些人更喜欢使用符号来在视觉上消除其代码中成员访问的歧义。
- 成员variables将被局部variables隐藏的地方
- 如果你只是想明确地说明你正在调用一个实例方法/variables
一些编码标准使用方法(2),因为他们声称它使代码更容易阅读。
例:
假设MyClass有一个名为“count”的成员variables
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)
但这似乎是常见的。
虽然我通常不是特别喜欢它,但我已经看到其他人使用这种方法来简单地从intellisense中获得帮助!
有很less的情况下,使用this
必须使用,还有其他的地方使用this
指针是解决问题的一种方法。
1) 可用选项 :解决局部variables和类成员之间的歧义, 如@ASk所示 。
2) 否替代:从成员函数返回一个指针或引用。 这经常在重载operator+
, operator-
, operator=
等时完成(并且应该完成):
class Foo { Foo& operator=(const Foo& rhs) { return * this; } };
这样做可以使用一种称为“ 方法链接 ”的习惯用法,即在一行代码中对对象执行多个操作。 如:
Student st; st.SetAge (21).SetGender (male).SetClass ("C++ 101");
有些人认为这个消费,其他人认为这是一种可憎的行为。 算上我后一组
3) 否替代:解决从属types中的名称。 这在使用模板时会出现,如下例所示:
#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) 可选scheme:作为编码风格的一部分,logging哪些variables是成员variables,而不是局部variables。 我更喜欢不同的命名scheme,其中成员varibales永远不能与当地人具有相同的名称。 目前,我正在使用mName
作为成员,并为当地人name
。
你需要使用this
来消除参数/局部variables和成员variables之间的歧义。
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将引用本地(参数或variables)myVar。 为了访问也称为myVar的类成员,你需要明确地使用“this->”。
其他用途(如我以为当我阅读摘要和一半的问题…),无视(坏)命名消歧在其他答案,如果你想转换当前对象,将其绑定到一个函数对象或者通过指向成员来使用它。
types转换
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
应该是一个参考,我完全同意。 我只想说,预编译器的一个丑陋的线可以模拟:
#define self (*this)
不要使用这个:-)
我在Effective C ++书中发现了另外一个显式使用“this”指针的有趣例子。
例如,假设你有一个const函数
unsigned String::length() const
你不想为每个调用计算String的长度,所以你想caching它做类似的事情
unsigned String::length() const { if(!lengthInitialized) { length = strlen(data); lengthInitialized = 1; } }
但是这不会编译 – 你正在改变const函数中的对象。
解决这个问题的技巧要求将其转换为非const的:
String* const nonConstThis = (String* const) this;
然后,你可以在上面做
nonConstThis->lengthInitialized = 1;
this
指针的主要目标(或者我可以说唯一的目的)是指向用于调用成员函数的对象。
基于这个目的,我们可以有一些情况,只有使用this
指针才能解决问题。
例如,我们必须返回成员函数中的调用对象,其参数是一个相同的类对象:
class human { ... human & human::compare(human & h){ if (condition) return h; // argument object else return *this; // invoking object } };