這個指標
所有非靜態成員函式都有一個隱藏引數,一個指向該類例項的指標,名為 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()
。