返回成员变量的引用是不好的做法吗?
Is returning references of member variables bad practice?
据说下面的方法比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&)
将引用(或指针)返回到类的内部是不好的,有几个原因。从(我认为)最重要的开始:
-
封装被破坏:你泄露了一个实现细节,这意味着你不能再随心所欲地改变你的类内部。例如,如果您决定不存储
first_
,而是动态地计算它,那么如何返回对它的引用呢? -
不变量不再是可持续的(在非const引用的情况下):任何人都可以随意访问和修改引用的属性,因此您无法"监视"其更改。这意味着您不能维护包含此属性的不变量。从本质上讲,你的类变成了一个blob。
-
Lifetime问题出现了:在属性所属的原始对象不存在之后,很容易保留对属性的引用或指针。这当然是未定义的行为。例如,大多数编译器都会尝试对在堆栈中保留对象的引用发出警告,但据我所知,没有编译器能够对函数或方法返回的引用产生这样的警告:您可以自己处理。
对于较小的值,通常通过复制传递它们就足够了(包括in
和out
),特别是现在有了move语义(在进入的路上)。
对于较大的值,这确实取决于情况,有时代理可能会减轻您的麻烦。
最后,请注意,对于某些类,拥有公共成员并不是那么糟糕。封装pair
的成员有什么意义?当您发现自己编写的类只不过是一组属性(没有任何不变式)时,与其让所有的OO都在我们身上,并为每个属性编写getter/setter对,不如考虑将它们设为public。
如果template
类型T
和U
是大结构体,那么按值返回是昂贵的。然而,你是正确的,通过引用返回相当于给予访问private
变量。为了解决这两个问题,将它们设置为 const
引用:
const T& First() const { return first_; }
const U& Second() const { return second_; }
注:此外,当没有setter方法时,在构造函数中保持变量未初始化是一种不好的做法。在原始代码中,First()
和Second()
似乎是first_
和second_
的包装器,它们意味着读/写。
答案取决于你想做什么。返回引用是促进数据结构变化的一种方便方法。一个很好的例子就是静态地图。它返回对元素的引用,即
std::map<int,std::string> a;
a[1] = 1;
没有什么可以阻止你做
auto & aref = a[1];
这一定是不好的做法吗?我不这么认为。我想说的是,如果你可以没有它,那就这样做。如果它使生活更方便和高效,使用它,并意识到你在做什么。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 将包含C样式数组的对象初始化为成员变量(C++)
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 在循环中按顺序遍历成员变量
- c++类声明时,相同的例程,不同的成员变量类型
- 如何从另一个文件继承私有成员变量和公共函数
- 在C++类中,是否必须初始化作为数组的成员变量
- 如何从子成员函数修改父公共成员变量
- 我可以在 C++ 中将数据成员/变量从其定义之外添加到结构中吗?
- 从私有成员变量的成员方法返回unique_ptr
- 在派生类中使用基类的私有成员变量的最佳方法
- 静态 constexpr 类成员变量对多线程读取是否安全?
- C++:是否可以使用非静态成员变量模板?
- 打印所有继承的类成员变量和方法
- 如何在复杂继承中访问静态成员变量
- 为什么我不能在返回 const 的布尔函数中为类成员变量赋值?C++
- 成员变量与函数概念检查