这个指针
所有非静态成员函数都有一个隐藏参数,一个指向该类实例的指针,名为 this
; 此参数以静默方式插入参数列表的开头,并由编译器完全处理。当在成员函数内访问类的成员时,通过 this
静默访问它; 这允许编译器对所有实例使用单个非静态成员函数,并允许成员函数以多态方式调用其他成员函数。
struct ThisPointer {
int i;
ThisPointer(int ii);
virtual void func();
int get_i() const;
void set_i(int ii);
};
ThisPointer::ThisPointer(int ii) : i(ii) {}
// Compiler rewrites as:
ThisPointer::ThisPointer(int ii) : this->i(ii) {}
// Constructor is responsible for turning allocated memory into 'this'.
// As the constructor is responsible for creating the object, 'this' will not be "fully"
// valid until the instance is fully constructed.
/* virtual */ void ThisPointer::func() {
if (some_external_condition) {
set_i(182);
} else {
i = 218;
}
}
// Compiler rewrites as:
/* virtual */ void ThisPointer::func(ThisPointer* this) {
if (some_external_condition) {
this->set_i(182);
} else {
this->i = 218;
}
}
int ThisPointer::get_i() const { return i; }
// Compiler rewrites as:
int ThisPointer::get_i(const ThisPointer* this) { return this->i; }
void ThisPointer::set_i(int ii) { i = ii; }
// Compiler rewrites as:
void ThisPointer::set_i(ThisPointer* this, int ii) { this->i = ii; }
在构造函数中,this
可以安全地用于(隐式或显式)访问已经初始化的任何字段或父类中的任何字段; 相反,(隐式或显式地)访问尚未初始化的任何字段或派生类中的任何字段是不安全的(由于尚未构造派生类,因此其字段既未初始化也未存在)。在构造函数中通过 this
调用虚拟成员函数也是不安全的,因为任何派生类函数都不会被考虑(由于派生类尚未构造,因此其构造函数尚未更新 vtable)。
还要注意,在构造函数中,对象的类型是构造函数构造的类型。即使将对象声明为派生类型,也是如此。例如,在下面的例子中,ctd_good
和 ctd_bad
在 CtorThisBase()
里面是 CtorThisBase
类型,在 CtorThis()
里面输入 CtorThis
,即使它们的规范类型是 CtorThisDerived
。由于派生的派生类是围绕基类构建的,所以实例逐渐遍历类层次结构,直到它成为其预期类型的完全构造的实例。
class CtorThisBase {
short s;
public:
CtorThisBase() : s(516) {}
};
class CtorThis : public CtorThisBase {
int i, j, k;
public:
// Good constructor.
CtorThis() : i(s + 42), j(this->i), k(j) {}
// Bad constructor.
CtorThis(int ii) : i(ii), j(this->k), k(b ? 51 : -51) {
virt_func();
}
virtual void virt_func() { i += 2; }
};
class CtorThisDerived : public CtorThis {
bool b;
public:
CtorThisDerived() : b(true) {}
CtorThisDerived(int ii) : CtorThis(ii), b(false) {}
void virt_func() override { k += (2 * i); }
};
// ...
CtorThisDerived ctd_good;
CtorThisDerived ctd_bad(3);
使用这些类和成员函数:
- 在好的构造函数中,对于
ctd_good
:CtorThisBase
是在输入CtorThis
构造函数时完全构造的。因此,s
在初始化i
时处于有效状态,因此可以被访问。i
在到达j(this->i)
之前初始化。因此,i
在初始化j
时处于有效状态,因此可以被访问。j
在到达k(j)
之前初始化。因此,j
在初始化k
时处于有效状态,因此可以被访问。
- 在错误的构造函数中,对于
ctd_bad
:k
在达到j(this->k)
后初始化。因此,k
在初始化j
时处于无效状态,并且访问它会导致未定义的行为。CtorThisDerived
直到CtorThis
构建完成后才构建。因此,b
在初始化k
时处于无效状态,并且访问它会导致未定义的行为。- 对象
ctd_bad
仍然是CtorThis
,直到它离开CtorThis()
,并且不会更新为使用CtorThisDerived
的 vtable 直到CtorThisDerived()
。因此,virt_func()
将调用CtorThis::virt_func()
,无论是打算叫那个还是CtorThisDerived::virt_func()
。