这个 Pointer CV-Qualifiers

this 也可以是 cv 限定的,与任何其他指针相同。但是,由于 this 参数未在参数列表中列出,因此需要特殊语法; cv 限定符列在参数列表之后,但在函数体之前。

struct ThisCVQ {
    void no_qualifier()                {} // "this" is: ThisCVQ*
    void  c_qualifier() const          {} // "this" is: const ThisCVQ*
    void  v_qualifier() volatile       {} // "this" is: volatile ThisCVQ*
    void cv_qualifier() const volatile {} // "this" is: const volatile ThisCVQ*
};

由于 this 是一个参数,因此可以根据其 this cv-qualifier 重载函数

struct CVOverload {
    int func()                { return    3; }
    int func() const          { return   33; }
    int func() volatile       { return  333; }
    int func() const volatile { return 3333; }
};

thisconst(包括 const volatile)时,该函数无法通过它写入成员变量,无论是隐式还是显式。唯一的例外是 mutable 成员变量 ,无论常量如何都可以写入。因此,const 用于指示成员函数不会更改对象的逻辑状态(对象对外界的显示方式),即使它确实修改了物理状态(对象在引擎盖下看起来的方式) )。

逻辑状态是对象对外部观察者的显示方式。它与物理状态没有直接联系,实际上甚至可能不会被存储为物理状态。只要外部观察者看不到任何变化,即使你翻转对象中的每一个位,逻辑状态也是恒定的。

物理状态,也称为按位状态,是对象存储在内存中的方式。这是对象的细节,构成其数据的原始 1 和 0。如果对象在内存中的表示永远不会改变,那么它只是物理上不变

请注意,C++基于逻辑状态而不是物理状态来定义 constness。

class DoSomethingComplexAndOrExpensive {
    mutable ResultType cached_result;
    mutable bool state_changed;

    ResultType calculate_result();
    void modify_somehow(const Param& p);

    // ...

  public:
    DoSomethingComplexAndOrExpensive(Param p) : state_changed(true) {
        modify_somehow(p);
    }

    void change_state(Param p) {
        modify_somehow(p);
        state_changed = true;
    }

    // Return some complex and/or expensive-to-calculate result.
    // As this has no reason to modify logical state, it is marked as "const".
    ResultType get_result() const;
};
ResultType DoSomethingComplexAndOrExpensive::get_result() const {
    // cached_result and state_changed can be modified, even with a const "this" pointer.
    // Even though the function doesn't modify logical state, it does modify physical state
    //  by caching the result, so it doesn't need to be recalculated every time the function
    //  is called.  This is indicated by cached_result and state_changed being mutable.

    if (state_changed) {
        cached_result = calculate_result();
        state_changed = false;
    }

    return cached_result;
}

请注意,虽然你在技术上可以this 上使用 const_cast 来使它成为非 cv 合格的,但你真的,真的不应该,而且应该使用 mutable 代替。当 const_cast 用于实际上 const 的对象时,它可能会调用未定义的行为,而 mutable 被设计为可以安全使用。但是,你可能会在极其旧的代码中遇到此问题。

此规则的一个例外是根据 const 访问器定义非 cv 限定的访问器; 因为如果调用非 cv 限定版本,对象被保证不是 const,那么就没有 UB 的风险。

class CVAccessor {
    int arr[5];

  public:
    const int& get_arr_element(size_t i) const { return arr[i]; }

    int& get_arr_element(size_t i) {
        return const_cast<int&>(const_cast<const CVAccessor*>(this)->get_arr_element(i));
    }
};

这可以防止不必要的代码重复。

与常规指针一样,如果 thisvolatile(包括 const volatile),则每次访问时都会从内存加载,而不是缓存。这对于优化具有与宣告任何其他指针 volatile 相同的效果,因此应该小心。

请注意,如果实例是 cv 限定的,则允许访问的唯一成员函数是成员函数,其 this 指针至少与实例本身一样是 cv 限定的:

  • 非 cv 实例可以访问任何成员函数。
  • const 实例可以访问 constconst volatile 函数。
  • volatile 实例可以访问 volatileconst volatile 函数。
  • const volatile 实例可以访问 const volatile 函数。

这是 const 正确性的关键原则之一。

struct CVAccess {
    void    func()                {}
    void  func_c() const          {}
    void  func_v() volatile       {}
    void func_cv() const volatile {}
};

CVAccess cva;
cva.func();    // Good.
cva.func_c();  // Good.
cva.func_v();  // Good.
cva.func_cv(); // Good.

const CVAccess c_cva;
c_cva.func();    // Error.
c_cva.func_c();  // Good.
c_cva.func_v();  // Error.
c_cva.func_cv(); // Good.

volatile CVAccess v_cva;
v_cva.func();    // Error.
v_cva.func_c();  // Error.
v_cva.func_v();  // Good.
v_cva.func_cv(); // Good.

const volatile CVAccess cv_cva;
cv_cva.func();    // Error.
cv_cva.func_c();  // Error.
cv_cva.func_v();  // Error.
cv_cva.func_cv(); // Good.