我对这两种设置值的可能性提出了疑问:
让我们说我得到了一个我要改变的课程。我正在使用这个:
void setfunc(std::string& st) { this->str = st; }
另一个能够完全相同的函数,但是使用字符串引用而不是用于设置值的void:
std::string& reffunc() { return this->str; }
现在,如果我要设置一个我可以使用的值:
std::string text("mytext");
setfunc(text);
//or
reffunc() = text;
现在我的问题是,如果使用设置值的第二种形式被认为是不好的。 没有性能差异。
答案 0 :(得分:3)
首先有getter和setter的原因是该类可以保护其不变量并且更容易修改。
如果您只有按值返回的setter和getter,那么您的类具有以下自由,而不会破坏API:
如果更改getter以返回const引用,就像有时保存副本一样,则会失去一些表示自由。您现在需要一个可以引用的返回类型的实际对象,其寿命足够长。您需要为返回值添加生命周期保证,例如承诺在使用非const成员之前,引用不会失效。您仍然可以返回对不是该类的直接成员的对象的引用,但可能是成员的成员(例如,返回对内部名称struct的第一个名称部分的引用)或者是一个解除引用的指针。
但是如果你通过非const引用返回,几乎所有的赌注都会被取消。由于客户端可以更改引用的值,因此在值更改时,您不能再依赖于被调用的setter和由正在执行的类控制的代码。您无法约束该值,也无法保留不变量。通过非const引用返回使得该类与具有公共成员的简单结构略有不同。
这导致我们选择最后一个选项,只需将数据成员公开。与返回非const引用的getter相比,您唯一丢失的是返回的对象不再是间接成员;它必须是一个直接的,真实的成员。
另一方面,性能和代码开销。每个getter和setter都是要编写的附加代码,还有额外的错误机会(为一个成员复制粘贴一个getter / setter对,为另一个成员创建相同的内容,然后忘记更改其中的一个变量?)。编译器可能会内联访问器,但如果它没有,则会产生调用开销。如果按值返回类似字符串的内容,则必须复制它,这很昂贵。
这是一种权衡,但大多数情况下,编写访问器会更好,因为它可以为您提供更好的封装和灵活性。
答案 1 :(得分:2)
我们无法看到成员str
的定义。
如果它是私有的,则您的reffunc()
会公开对私人会员的引用;你正在写一个违反你设计的功能,所以你应该重新考虑你正在做的事情。
此外,它是一个引用,因此在使用该引用时,您必须确保包含str
的对象仍然存在。
此外,您正在展示外部实施细节,可能会在未来发生变化,更改界面本身(如果str
变得不同,setfunc()
的实施可以进行调整,{{1}签名必须改变。)
你所写的并没有错,但它可能以错误的方式使用。你正在减少封装。这是一个设计选择。
答案 2 :(得分:1)
没关系。但是,你必须注意这些陷阱:
引用的对象是可修改的。当您返回非const
引用时,您将公开数据而不会受到修改的保护。显而易见,但无论如何要注意这一点!
引用的对象可以脱离sope。如果引用的对象的生命周期结束,访问引用将是未定义的行为。但是,它们可以用来延长临时工作的寿命。
答案 3 :(得分:1)
您使用reffunc()
函数的方式被认为是错误的编码。但是(正如评论中所提到的),一般来说,返回引用并不是错误的编码。
这就是reffunc() = text;
被视为错误编码的原因:
人们通常不希望在作业的左侧进行函数调用,而是在右侧。查看函数调用时的自然期望是它计算并返回一个值(或rvalue,预计在赋值的右侧)而不是引用(或左值,预计在左侧)任务的一方)。
因此,通过在赋值的左侧放置函数调用,您将使代码更复杂,因此可读性更低。请记住,你没有任何其他动机(正如你所说,性能是相同的,通常是在这些情况下),良好的编码建议你使用" set"功能
阅读好书"Clean Code",了解有关清洁编码的更多问题。
至于函数中的返回引用,这是问题的标题,它并不总是编码错误,有时需要更清晰,更简洁的代码。特别是如果你返回一个引用(参见std :: vector中的operator []和通常帮助代码变得更易读和更简单的赋值运算符),c ++中的许多运算符重载功能都能正常工作。请参阅注释。