避免在 const 和非 const getter 方法中重複程式碼

在 C++中,只有 const 限定符的方法可以過載。有時可能需要兩個版本的 getter 返回對某個成員的引用。

Foo 成為一個類,它有兩個執行相同操作的方法,並返回對 Bar 型別的物件的引用:

class Foo
{
public:
    Bar& GetBar(/* some arguments */)
    {
        /* some calculations */
        return bar;
    }
    
    const Bar& GetBar(/* some arguments */) const
    {
        /* some calculations */
        return bar;
    }

    // ...
};

它們之間的唯一區別是一個方法是非 const 並返回一個非 const 引用(可用於修改物件),第二個是 const 並返回 const 引用。

為了避免程式碼重複,有一種誘惑從另一種方法中呼叫一種方法。但是,我們不能從 const 中呼叫非 const 方法。但我們可以從非 const 方法呼叫 const 方法。這將需要使用’const_cast’來刪除 const 限定符。

解決方案是:

struct Foo
{
    Bar& GetBar(/*arguments*/)
    {
        return const_cast<Bar&>(const_cast<const Foo*>(this)->GetBar(/*arguments*/));
    }
    
    const Bar& GetBar(/*arguments*/) const
    {
        /* some calculations */
        return foo;
    }
};

在上面的程式碼中,我們通過將其轉換為 const 型別:const_cast<const Foo*>(this),從非 const GetBar 呼叫 GetBar 的 const 版本。因為我們從非 const 呼叫 const 方法,所以物件本身是非 const 的,並且允許拋棄 const。

檢查以下更完整的示例:

#include <iostream>

class Student
{
public:
    char& GetScore(bool midterm)
    {
        return const_cast<char&>(const_cast<const Student*>(this)->GetScore(midterm));
    }
    
    const char& GetScore(bool midterm) const
    {
        if (midterm)
        {
            return midtermScore;
        }
        else
        {
            return finalScore;
        }
    }
    
private:
    char midtermScore;
    char finalScore;
};

int main()
{
    // non-const object
    Student a; 
    // We can assign to the reference. Non-const version of GetScore is called
    a.GetScore(true) = 'B';
    a.GetScore(false) = 'A';
    
    // const object
    const Student b(a); 
    // We still can call GetScore method of const object,
    // because we have overloaded const version of GetScore
    std::cout << b.GetScore(true) << b.GetScore(false) << '\n'; 
}