這個 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.