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

Can I use const references instead of getter functions?

本文关键字:getter 函数 可以使 常量 引用 我可以      更新时间:2023-10-16

我只是想知道如果我只允许一个 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. 我仍然可以修改类的内部,引用变量提供了一个抽象层。

弊:

  1. 我没有getter函数,而是一堆引用。这将增加对象大小。
  2. const_cast,人家可以搞砸私人成员,但这些人很淘气吧?

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

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

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

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

这三件事意味着您提出的const参考反模式是无法启动的。别这样!

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

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

getter 的另一个优点是,在调试版本中,您可以对返回的数据添加额外的检查/断言。

最后,编译器将内联您的 getter 函数,这将产生与您提出的代码类似的代码。

一些额外的缺点:

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

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

相反,您需要确保周围结构的常量正确性(这会自动为您提供对成员的常量访问权限(,并且只是让成员成为它们逻辑上需要的任何内容。

请务必阅读何时可以、应该或可以与公共数据成员切换 getter 和 setter。例如,请参阅此问题。请注意,如果您更改界面,则预示的setter/getter的优势是调用getter不会影响调用站点。现实似乎并非如此,例如,重构一个成员及其所有接入点对于任何有自尊心的C++代码编辑器来说都是一个微不足道的操作。

虽然有人可能会争论封装,但我更强烈地主张常量正确性,这减轻了对大量封装的需求,并且确实大大简化了代码。