这个指针

所有非静态成员函数都有一个隐藏参数,一个指向该类实例的指针,名为 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_goodctd_badCtorThisBase() 里面是 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()