是否返回了访问者惯用语的参考?

时间:2011-03-09 17:46:20

标签: c++ reference idioms accessor

在C ++中,可以创建一个访问器,它返回对私有字段的引用。

class Cls {
    private:
        int _attr;
    public:
        int& attr() { return _attr; }
};

这样可以按原样访问该属性:

// set
c.attr() = 4;

// get
cout << c.attr() << endl;

这种访问者风格是否惯用/良好实践?一个普通的C ++程序员会看到这种访问者的风格吗? (提示:我第一次看到这个时感到很惊讶,但有点喜欢这种风格)

8 个答案:

答案 0 :(得分:10)

假设您需要保证:

template <int Base>
class Digit {
  private:
    int attr_; // leading underscore names are reserved!
  public:
    int attr() const { return attr_; }
    void attr(int i) { attr_ = i % Base; } // !
};

在这种情况下,您无法返回引用,因为无法保证用户不会以您不想要的方式修改它。这是使用setter的主要原因 - 您可以(现在或以后)过滤输入以确保它是可接受的。有了参考,您必须盲目地接受用户分配给您的会员的内容。那时,为什么不公开呢?

答案 1 :(得分:7)

不,只要您还提供const重载,该代码就不足为奇了:

class Cls {
    int _attr;
public:
    int& attr() { return _attr; }
    int const& attr() const { return _attr; }
};

但是,出于Chris Lutz和Mark B提到的原因,我会考虑以下惯用语:

class Cls {
    int _attr;
public:
    int const& attr() const { return _attr; }
    void attr(int i) { _attr = i; }
};

答案 2 :(得分:5)

通常,对于非平凡类(例如可以简单地定义为struct的类),为特定属性提供访问器/增变器可能是代码气味。通常,类应该倾向于保持其内部状态:内部。如果你提供一个非const引用内部状态,那么突然间你根本无法控制类不变量。这不仅会使调试变得更加困难,因为可能的状态更改范围是整个项目,它会阻止您更改类的内部,因为它们实际上都是状态和用户API。

相反,你应该设计一些方法,在保持类不变量的同时对你的类执行有意义的工作。在某些情况下,提供对特定状态变量的只读访问权限是完全正常的,而在其他情况下,您只希望以另一种方式提供对结束状态的访问。

答案 3 :(得分:5)

这样做完全违背了首先将其设为私有的目的。

访问器的目的是以这样一种方式公开内部状态:当外部代码尝试修改状态时,类可以维护不变量(通过仅允许读访问,或者在修改状态之前验证写访问) ;它们通常看起来像

int  attr() const {return _attr;}
void attr(int a)  {_attr = a;}

如果将来需要约束属性可以采用的值,或者更改它在内部存储的方式,那么您可以在不更改类接口的情况下修改这些属性的实现。

如果没有必要(并且你已经决定永远不需要),那就公开一下;将它作为参考公开只会获得几行不必要的代码和使用它时的古怪语法。

答案 4 :(得分:4)

这取决于。如果类的作用是包含这些对象(例如 一个容器类),然后它非常惯用,而且是正常的做法 的东西。然而,在大多数其他情况下,它被认为是优选的 使用getter和setter方法。不一定名为getXxx和 setXxx ---我见过的最常用的命名约定是使用m_attr 属性的名称,只需attr两个名称 吸气剂和二传手。 (操作员重载将在它们之间进行选择 根据论点的数量。)

- 詹姆斯坎泽

答案 5 :(得分:2)

返回对POD成员的引用通常不太常见。我认为读者必须期望为此目的安装。但是,如果你这样做,不要忘记为const情况重载它。

答案 6 :(得分:2)

它相对频繁,但风格很糟糕。

例如,如果您查看STL,您会注意到产生const&&内部状态的类通常是普通容器,并且仅提供此类访问权限你实际存放在他们身上的东西。显然,您无法直接修改size等属性或二叉树的内部节点。

提供对元素的直接访问会破坏封装。您不仅会失去对这些元素的所有类不变量,而且还会使它们成为API的一部分,因此在不更新所有客户端的情况下也无法更改类的实现。

就我而言,它们是C ++中的两种类型:

struct BigBag {
  Foo _foo;
  Bar _bar;
  FooBar _foobar;
};

class MyClass {
public:
  explicit MyClass(int a, int b);

  int getSomeInfo();

  void updateDetails(int a, int b);
private:
  // no peeking
};

即:它只是一个相关元素的集合,在这种情况下,一切都是公开的,你已经完成了,或者有类不变量和/或你关心它的API,因为有很多客户端代码,在这种情况下,您不会公开 实施细节。

答案 7 :(得分:0)

以防你想要摆脱括号......

class Cls {
    private:
        int _attr;
    public:
        Cls() : attr(_attr) { }
        int& attr;
};

编辑:克里斯的观点很好。使用公共引用包装私有变量基本上没有任何结果。以下版本确实添加了一些内容。使引用const阻止设置但允许获取私有变量。

class Cls {
    private:
        int _attr;
    public:
        Cls() : attr(_attr) { }
        int const & attr;
};