54

据说以下内容比将 First() 和 Second() 作为公共成员更好。我相信这几乎同样糟糕。

// Example 17-3(b): Proper encapsulation, initially with inline accessors. Later
// in life, these might grow into nontrivial functions if needed; if not, then not.

template<class T, class U>
class Couple {
public:
  Couple()           : deleted_(false) { }
  void MarkDeleted() { deleted_ = true; }
  bool IsDeleted()   { return deleted_; }

private:
 T first_;
 U second_;
 bool deleted_;
 T& First()         { return first_; }
 U& Second()        { return second_; }
};

如果您要提供一种访问类外部私有变量的方法,那有什么意义呢?功能不应该是

T First(); void(or T) First(const T&)
4

3 回答 3

63

将引用(或指针)返回到类的内部是不好的,有几个原因。从(我认为是)最重要的开始:

  1. 封装被破坏:你泄露了一个实现细节,这意味着你不能再随心所欲地改变你的类内部结构。例如,如果您决定不存储first_,而是动态计算它,您将如何返回对它的引用?你不能,因此你被卡住了。

  2. 不变量不再可持续(在非常量引用的情况下):任何人都可以随意访问和修改引用的属性,因此您无法“监视”其更改。这意味着您不能维护该属性所属的不变量。从本质上讲,您的班级正在变成一团。

  3. 生命周期问题出现了:在它们所属的原始对象不复存在后,很容易保留对属性的引用或指针。这当然是未定义的行为。例如,大多数编译器会尝试警告在堆栈上保留对对象的引用,但我知道没有编译器能够为函数或方法返回的引用产生这样的警告:你只能靠你自己。

因此,通常最好不要放弃对属性的引用或指针。甚至不是 const 的!

对于小值,通常通过复制(inout)传递它们就足够了,尤其是现在使用移动语义(在传入的过程中)。

对于较大的值,这实际上取决于情况,有时代理可能会减轻您的麻烦。

最后,请注意,对于某些类,拥有公共成员并不是那么糟糕。封装 a 的成员有什么意义pair?当您发现自己编写的类不过是属性的集合(没有任何不变量)时,与其让所有 OO 集中在我们身上并为它们中的每一个编写一个 getter/setter 对,不如考虑将它们公开。

于 2011-11-04T07:25:40.650 回答
32

如果template类型TU是大结构,那么按值返回是昂贵的。但是,您是正确的,通过引用返回等同于授予对private变量的访问权限。要解决这两个问题,请const参考

const T& First()  const  { return first_; }
const U& Second() const  { return second_; }

PS此外,当没有 setter 方法时,在构造函数中保持变量未初始化是一种不好的做法。似乎在原始代码中,First()并且Second()是包装器,first_用于second_读/写两者。

于 2011-11-04T06:19:33.057 回答
8

答案取决于一个人想要做什么。返回引用是促进数据结构突变的一种便捷方式。一个很好的例子是 stl 映射。它返回对元素的引用,即

std::map<int,std::string> a;
a[1] = 1;

没有什么可以阻止你做

auto & aref = a[1];

这一定是一种不好的做法吗?我不这么认为。我会说,如果你可以不用它就这样做。如果它使生活更加方便和高效,请使用它并注意您在做什么。

于 2014-03-05T16:56:10.407 回答