成員函式 cv-qualifier 過載

當通過對該類的 cv 限定引用訪問類中的函式時,它們可以過載; 這最常用於 const 的過載,但也可以用於 volatileconst volatile 的過載。這是因為所有非靜態成員函式都將 this 作為隱藏引數,cv-qualifiers 應用於該引數。這最常用於 const 的超載,但也可用於 volatileconst volatile

這是必要的,因為只有當成員函式至少與呼叫它的例項一樣符合 cv 限定時才能呼叫它。雖然非 const 例項可以同時呼叫 const 和非 const 成員,但 const 例項只能呼叫 const 成員。這允許函式根據呼叫例項的 cv 限定符具有不同的行為,並允許程式設計師通過不提供具有該限定符的版本來禁止不期望的 cv 限定符的函式。

具有一些基本的 print 方法的類可能會像這樣過載:

#include <iostream>

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        void print()
        {
            std::cout << "int: " << i << std::endl;
        }

        void print() const
        {
            std::cout << "const int: " << i << std::endl;
        }

    protected:
        int i;
};

int main()
{
    Integer i{5};
    const Integer &ic = i;
    
    i.print(); // prints "int: 5"
    ic.print(); // prints "const int: 5"
}

這是 const 正確性的一個關鍵原則:通過將成員函式標記為 const,允許在 const 例項上呼叫它們,這反過來允許函式將例項作為 const 指標/引用(如果它們不需要修改它們)。這允許程式碼指定它是否通過將未修改的引數(如 const)和修改後的引數(不具有 cv-qualifiers)修改為狀態,從而使程式碼更安全且更易讀。

class ConstCorrect 
{
  public:
    void good_func() const 
    {
        std::cout << "I care not whether the instance is const." << std::endl;
    }

    void bad_func() 
    {
        std::cout << "I can only be called on non-const, non-volatile instances." << std::endl;
    }
};

void i_change_no_state(const ConstCorrect& cc) 
{
    std::cout << "I can take either a const or a non-const ConstCorrect." << std::endl;
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Error.  Can only be called from non-const instance.
}

void const_incorrect_func(ConstCorrect& cc) 
{
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Good.  Can only be called from non-const instance.
}

這種情況的一個常見用法是將訪問器宣告為 const,將 mutator 宣告為非 const

const 成員函式中不能修改類成員。如果你確實需要修改某個成員,例如鎖定 std::mutex,則可以將其宣告為 mutable

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        int get() const
        {
            std::lock_guard<std::mutex> lock{mut};
            return i;
        }

        void set(int i_)
        {
            std::lock_guard<std::mutex> lock{mut};
            i = i_;
        }

    protected:
        int i;
        mutable std::mutex mut;
};