避免在 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'; 
}