我什么时候应该在方法中显式地写
this->member
一个班?
通常,您不必这样做,
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
}
};
如果在方法中声明与现有成员同名的局部变量,则必须使用 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
您可能需要显式使用
this
指针有多种原因。
虽然我通常不太喜欢它,但我看到其他人使用它->只是为了从智能感知中获得帮助!
在极少数情况下必须使用
this
,而在其他情况下,使用 this
指针是解决问题的一种方法。
可用替代方案:为了解决局部变量和类成员之间的歧义,如@ASk所示。
没有替代方案: 从成员函数返回指向 this
的指针或引用。当超载
operator+
、
operator-
、
operator=
等时,经常会这样做(并且应该这样做):
class Foo
{
Foo& operator=(const Foo& rhs)
{
return * this;
}
};
这样做允许一种称为“方法链接”的习惯用法,您可以在一行代码中对一个对象执行多个操作。如:
Student st;
st.SetAge (21).SetGender (male).SetClass ("C++ 101");
有些人认为这很简洁,另一些人则认为这是令人厌恶的。算我在后一组吧。
没有替代方案: 解析依赖类型中的名称。使用模板时会出现这种情况,如下例所示:
#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";
}
可用替代方案:作为编码风格的一部分,记录哪些变量是成员变量而不是局部变量。我更喜欢不同的命名方案,其中成员变量永远不能与本地变量具有相同的名称。目前,我对会员使用 mName
,对当地人使用
name
。
一些编码标准使用方法(2),因为他们声称它使代码更易于阅读。
假设 MyClass 有一个名为“count”的成员变量
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)
但这似乎很常见。
演员表
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。
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
来消除参数/局部变量和成员变量之间的歧义。
class Foo
{
protected:
int myX;
public:
Foo(int myX)
{
this->myX = myX;
}
};
this
指针的主要(或者我可以说,唯一)目的是它指向用于调用成员函数的对象。基于这个目的,我们可以有一些情况只使用
this
指针就可以解决问题。例如,我们必须在参数为同一个类对象的成员函数中返回调用对象:
class human {
...
human & human::compare(human & h){
if (condition)
return h; // argument object
else
return *this; // invoking object
}
};
例如,假设您有一个 const 函数,例如
unsigned String::length() const
您不想计算每次调用的字符串长度,因此您想缓存它,执行类似的操作
unsigned String::length() const
{
if(!lengthInitialized)
{
length = strlen(data);
lengthInitialized = 1;
}
}
但这不会编译 - 您正在 const 函数中更改对象。
解决这个问题的技巧需要将
this 转换为非常量 this:
String* const nonConstThis = (String* const) this;
然后,你就可以做上面的事情了
nonConstThis->lengthInitialized = 1;