我可以使用 const 引用而不是 getter 函数吗?

Can I use const references instead of getter functions?

我只是想知道如果我只允许一个const引用变量,我是否可以绕过使用getters,如下

#include <string>

class cTest
{
    private:
        int m_i;
        std::string m_str;

    public:
        const int & i;
        const std::string & str;

    cTest(void)
    : i(m_i)
    , str(m_str)
    {}
};

int main(int argc, char *argv[])
{
    cTest o;
    int i = o.i; // works
    o.i += 5; // fails
    o.str.clear(); // fails

    return 0;
}

我想知道为什么人们似乎根本不这样做。我缺少一些严重的缺点吗?请贡献优点和缺点列表,并在必要时进行纠正。

优点:

  1. 通过调用 getter 函数没有开销。
  2. 由于功能较少,程序大小有所减少。
  3. 我仍然可以修改 class 的内部结构,引用变量提供了一个抽象层。

缺点:

  1. 而不是 getter 函数,我有一堆参考。这会增加对象大小。
  2. 使用const_cast,人们可以把私人成员搞得一团糟,但这些人很恶作剧,对吧?

确实有一些严重的缺点(除了你也提到的第二个缺点,我也把它放在 "severe" 类别中):

1) 您需要提供(并因此维护)一个复制构造函数:编译器默认情况下将不起作用。

2) 您需要提供一个赋值运算符:编译器默认情况下不起作用。

3) 仔细考虑实现移动语义。同样,编译器默认值将不起作用。

这三件事意味着您提出的 const 参考反模式是行不通的。不要这样做!

getter 函数的一个优点是您可能在某个时间点 - 想要更改 returned 值 - 而没有 getter 函数你无法做到。这个场景实际上需要你 return 非引用,这在 c++ 中不太常见。 [edit] 但是使用移动语义而不是引用这应该是可行的[/edit]

您可能还想在 getter 函数中放置一个断点以了解谁在读取它的值,您可能想添加日志记录等。这称为 封装。

getter 的另一个优点是,在调试版本中,您可以在 returned 数据上添加额外的 checks/asserts。

最终编译器将内联您的 getter 函数,这将生成与您建议的代码相似的代码。

一些额外的缺点:

1) 模板代码将希望使用函数调用获取值,即。 size(),如果你改成const& variable,那么你将无法在某些模板中使用它。所以这是一个一致性问题。

如果您想避免 getters 和 setter,使用 const 引用成员不是解决方案。

相反,您需要确保周围结构的 const 正确性(这会自动为您提供对成员的 const 访问权限),并让成员成为逻辑上需要的任何成员。

请务必阅读 getter 和设置器何时可以、应该或可以与 public 数据成员切换。参见例如this question。请注意,如果您更改界面,setters/getters 的先驱优势是调用 getter 不会影响调用站点。现实似乎并非如此,例如重构成员及其所有访问点对于任何自尊的 C++ 代码编辑器来说都是微不足道的操作。

虽然有人会赞成封装,但我更强烈地赞成 const 的正确性,这减轻了对大量封装的需求,并确实大大简化了代码。