Getter 和 setter、指针或引用以及在 C++ 中使用的良好语法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1596432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getter and setter, pointers or references, and good syntax to use in c++?
提问by Jonathan
I would like to know a good syntax for C++ getters and setters.
我想知道 C++ getter 和 setter 的良好语法。
private:
YourClass *pMember;
the setter is easy I guess:
我猜二传手很容易:
void Member(YourClass *value){
this->pMember = value; // forget about deleting etc
}
and the getter? should I use references or const pointers?
和吸气剂?我应该使用引用还是常量指针?
example:
例子:
YourClass &Member(){
return *this->pMember;
}
or
或者
YourClass *Member() const{
return this->member;
}
whats the difference between them?
它们之间有什么区别?
Thanks,
谢谢,
Joe
乔
EDIT:
编辑:
sorry, I will edit my question... I know about references and pointers, I was asking about references and const pointers, as getters, what would be the difference between them in my code, like in hte future, what shoud I expect to lose if I go a way or another...
抱歉,我会编辑我的问题......我知道引用和指针,我问的是引用和常量指针,作为吸气剂,它们在我的代码中的区别是什么,比如在未来,我应该期待什么如果我走一条路,就会失去...
so I guess I will use const pointers instead of references
所以我想我会使用 const 指针而不是引用
const pointers can't be delete or setted, right?
const 指针不能被删除或设置,对吗?
回答by RED SOFT ADAIR
As a general law:
作为一般法律:
- If NULL is a valid parameter or return value, use pointers.
- If NULL is NOTa valid parameter or return value, use references.
- 如果 NULL 是有效参数或返回值,请使用指针。
- 如果 NULL不是有效的参数或返回值,请使用引用。
So if the setter should possibly be called with NULL, use a pointer as a parameter. Otherwise use a reference.
因此,如果应该使用 NULL 调用 setter,请使用指针作为参数。否则使用参考。
If it's valid to call the getter of a object containing a NULL pointer, it should return a pointer. If such a case is an illegal invariant, the return value should be a reference. The getter then should throw a exception, if the member variable is NULL.
如果调用包含 NULL 指针的对象的 getter 是有效的,它应该返回一个指针。如果这种情况是非法的不变量,则返回值应该是引用。如果成员变量为 NULL,则 getter 应该抛出异常。
回答by DevFred
The best thing is to provide a real OO interface to the client that hides implementaton details. Getters and Setters are not OO.
最好的办法是为隐藏实现细节的客户端提供一个真正的 OO 接口。Getter 和 Setter 不是面向对象的。
回答by Jerry Coffin
Your code looks a great deal as if you're accustomed to a different language -- in C++ using this->x
(for one example) is relatively unusual. When the code is at all well written, so is using an accessor or mutator.
你的代码看起来很像你习惯了一种不同的语言——在 C++ 中使用this->x
(例如)是相对不寻常的。当代码写得很好时,使用访问器或修改器也是如此。
Though I'm fairly unusual in this particular respect, I'll go on record (yet again) as saying that forcing client code to use an accessor or mutator directly is a bad idea. If you honestly have a situation where it makes sense for client code to manipulate a value in your object, then the client code should use normal assignment to read and/or write that value.
虽然我在这方面相当不寻常,但我会继续记录(再次)说强制客户端代码直接使用访问器或修改器是一个坏主意。如果您确实遇到这样的情况,客户端代码可以操作对象中的值,那么客户端代码应该使用正常赋值来读取和/或写入该值。
When/if you need to control what value is assigned, operator overloading lets you take that control without forcing ugly get/set syntax on the client code. Specifically, what you want is a proxy class (or class template). Just for one example, one of the most common situations where people want get/set functions is something like a number that's supposed to be restricted to some particular range. The setXXX
checks the new value for being in range, and the getXXX
returns the value.
当/如果您需要控制分配的值,运算符重载让您可以进行控制,而无需在客户端代码上强制使用丑陋的 get/set 语法。具体来说,您想要的是代理类(或类模板)。仅举一个例子,人们想要获取/设置函数的最常见情况之一是应该限制在某个特定范围内的数字。该setXXX
检查在范围内的新的值,并且getXXX
返回该值。
If you want that, a (fairly) simple template can do the job much more cleanly:
如果你想要,一个(相当)简单的模板可以更干净地完成这项工作:
template <class T, class less=std::less<T> >
class bounded {
const T lower_, upper_;
T val_;
bool check(T const &value) {
return less()(value, lower_) || less()(upper_, value);
}
void assign(T const &value) {
if (check(value))
throw std::domain_error("Out of Range");
val_ = value;
}
public:
bounded(T const &lower, T const &upper)
: lower_(lower), upper_(upper) {}
bounded(bounded const &init)
: lower_(init.lower), upper_(init.upper)
{
assign(init);
}
bounded &operator=(T const &v) { assign(v); return *this; }
operator T() const { return val_; }
friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >> temp;
if (b.check(temp))
is.setstate(std::ios::failbit);
else
b.val_ = temp;
return is;
}
};
This also makes the code much closer to self documenting -- for example, when you declare an object like: bounded<int>(1, 1024);
, it's immediately apparent that the intent is an integer in the range of 1 to 1024. The only part somebody mightfind open to question is whether 1 and/or 1024 is included in the range. This is considerably different from defining an int in the class, and expecting everybody who ever looks at the class to realize that they're supposed to use the setXXX to enforce some (at that point unknown) set of bounds on the values that can be assigned.
这也使得代码更接近自我记录-例如,当你声明类似于对象:bounded<int>(1, 1024);
,这是显而易见的是,其意图是在1至1024的整数。只有一部分人可能会发现开放的问题是范围内是否包含 1 和/或 1024。这与在类中定义 int 有很大不同,并期望每个看过该类的人都意识到他们应该使用 setXXX 来强制执行一些(在那时未知的)值的一组边界,这些边界可以是分配。
When you embed one of these in a class, you make it a public variable, and the range is still enforced. In the client code, there's no real argument over syntax -- you're just assigning to a public variable, like you would any other -- with the minor detail that attempting to assign a value that's out of range will throw an exception. In theory, the class should probably take a policy template-parameter to specify exactly what it does in that case, but I've never had a real reason to bother with that.
当您在类中嵌入其中之一时,您将其设为公共变量,并且仍然强制执行范围。在客户端代码中,没有关于语法的真正争论——你只是分配给一个公共变量,就像你对任何其他变量一样——还有一些小细节,即试图分配一个超出范围的值会引发异常。从理论上讲,该类可能应该采用策略模板参数来准确指定它在这种情况下的作用,但我从来没有真正有理由为此烦恼。
回答by Boojum
As others have said, use pointers if null is a possibility.
正如其他人所说,如果可能为 null,请使用指针。
In most cases, I prefer to use references when possible. Personally, in my code, I like to use the distinction between pointers and references to signal ownership. I think of calls with references as "loaning" an object to another function or class. The original class that passed or returned the reference still owns it, and is responsible for its creation, maintenance and clean up. When my code passes a non-const pointer, on the other hand, it usually means that there's some kind of transfer or sharing of ownership going on, with all the responsibilities that entails.
在大多数情况下,我更喜欢尽可能使用引用。就我个人而言,在我的代码中,我喜欢使用指针和引用之间的区别来表示信号所有权。我认为带有引用的调用是将对象“借给”另一个函数或类。传递或返回引用的原始类仍然拥有它,并负责它的创建、维护和清理。另一方面,当我的代码传递一个非常量指针时,通常意味着正在进行某种所有权的转移或共享,并承担所有责任。
(And yes, I usually use smart pointers. Those are akin to references in my mind. I'm talking about lower level code than that here.)
(是的,我通常使用智能指针。这些类似于我脑海中的引用。我说的是比这里低级的代码。)
回答by sbk
In addition to the other answers, if you choose references for the getter don't write it like in your example:
除了其他答案之外,如果您为 getter 选择引用,请不要像在您的示例中那样写:
YourClass &Member(){
return *this->pMember;
}
Your getter actually allows setting, as in instance->Member() = YourClass();
and thus bypassing your setter. This might not be allowed if YourClass is noncopyable, but is still another thing to have in mind. Another drawback is the getter is not const.
你的 getter 实际上允许设置,就像在instance->Member() = YourClass();
并绕过你的 setter 一样。如果 YourClass 是不可复制的,这可能是不允许的,但仍然是另一件需要记住的事情。另一个缺点是 getter 不是 const。
Instead, write your getter like this:
相反,像这样写你的吸气剂:
const YourClass &Member() const {
return *this->pMember;
}
回答by Doug T.
whats the difference between them?
它们之间有什么区别?
The reference is an alias of the thing(it isthe thing*). A pointer is the address of the thing. If there's a chance that what's pointed to won't be there, then you probably don't want to return references. References tell the caller "I'm going to give you an alias that will exist when I return it to you". In fact there's really no way to check the reference to see if what's underlying is valid.
引用是事物的别名(它是事物*)。指针是事物的地址。如果有可能指向的内容不存在,那么您可能不想返回引用。引用告诉调用者“我将给你一个别名,当我将它返回给你时它就会存在”。事实上,真的没有办法检查引用以查看底层内容是否有效。
With the pointer, semantically, you are implying that the caller may wish to check to see if Member exists before using it. Ussually this is done with a NULL check.
使用指针,在语义上,您暗示调用者可能希望在使用之前检查 Member 是否存在。通常这是通过 NULL 检查完成的。
Ultimately there's no "right" answer. It depends on the class's contract and if the caller will/should/wants to check whether "Member" is still around.
最终没有“正确”的答案。这取决于类的合同以及调用者是否愿意/应该/想要检查“成员”是否还在。
The short answer is pointers for things that can be pointed elsewhere and references for "unseated" aliases.
简短的回答是可以指向其他地方的事物的指针和“未安装”别名的引用。
回答by Ben
+1 on questioning the use of setters and getters. If you must use them and have the possibility of nulls consider using boost::shared_ptr. This way ownership is handled for you.
+1 质疑 setter 和 getter 的使用。如果您必须使用它们并且有可能出现空值,请考虑使用 boost::shared_ptr。通过这种方式为您处理所有权。
回答by DevFred
Jonathan, what compiler are you using? There's a great chance that shared_ptr
already comes shipped with it as part of the compiler's TR1 implementation.
乔纳森,你用的是什么编译器?很有可能它shared_ptr
已经作为编译器 TR1 实现的一部分随附了。