C# get 和 set 函数是否受 C++ 程序员欢迎?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/737409/
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
Are get and set functions popular with C++ programmers?
提问by Nick Bolton
I'm from the world of C# originally, and I'm learning C++. I've been wondering about get and set functions in C++. In C# usage of these are quite popular, and tools like Visual Studio promote usage by making them very easy and quick to implement. However, this doesn't seem to be the case in the C++ world.
我最初来自 C# 的世界,我正在学习 C++。我一直想知道 C++ 中的 get 和 set 函数。这些在 C# 中的使用非常流行,并且像 Visual Studio 这样的工具通过使它们非常容易和快速实现来促进使用。但是,在 C++ 世界中似乎并非如此。
Here's the C# 2.0 code:
这是 C# 2.0 代码:
public class Foo
{
private string bar;
public string Bar
{
get { return bar; }
set { bar = value; }
}
}
Or, in C# 3.0:
或者,在 C# 3.0 中:
public class Foo { get; set; }
May people will say, well whats the point in that? Why not just create a public field and then make it a property later if you need to; honestly, I'm actually not sure. I just do it out of good practice because I've seen it done so many times.
可能人们会说,那有什么意义呢?为什么不直接创建一个公共字段,然后在需要时将其设为属性呢?老实说,我实际上不确定。我只是出于良好的实践而这样做,因为我已经看过很多次了。
Now because I'm so used to doing it, I feel like I should carry over the habit to my C++ code, but is this really necessary? I don't see it done as often as with C#.
现在因为我太习惯了,我觉得我应该把这个习惯延续到我的 C++ 代码中,但这真的有必要吗?我没有看到它像 C# 那样经常完成。
Anyway, here's the C++ from what I gather:
无论如何,这是我收集到的 C++:
class Foo
{
public:
std::string GetBar() const; // Thanks for the tip, @Daniel Earwicker.
void SetBar(std::string bar);
private:
std::string bar;
}
std::string Foo::GetBar() const
{
return bar;
}
void Foo::SetBar(std::string bar)
{
// Also, I always wonder if using 'this->' is good practice.
this->bar = bar;
}
Now, to me that seems like a whole lot of leg work; considering using Visual Studio's tools the C# implementation would take literally seconds to implement, and the C++ took me a lot longer to type - I feel its not worth the effort, especially when the alternative is 5 lines long:
现在,对我来说,这似乎是大量的腿部工作;考虑使用 Visual Studio 的工具,C# 实现需要几秒钟才能实现,而 C++ 需要我花费更长的时间来输入 - 我觉得它不值得付出努力,尤其是当替代方案有 5 行长时:
class Foo
{
public:
std::string Bar;
}
From what I gather, these are the advantages:
从我收集到的,这些是优点:
- You can change implementation details for the get and set functions, so instead of returning a private field you can return something more interesting.
- You can remove a get/set later on and make it read/write only (but for a public facing interface, this seems, not good).
- 您可以更改 get 和 set 函数的实现细节,因此您可以返回更有趣的东西,而不是返回私有字段。
- 您可以稍后删除 get/set 并使其只能读/写(但对于面向公众的界面,这似乎并不好)。
And the disadvantages:
和缺点:
- Takes ages to type, is this reallyworth the effort? Generally speaking. In some cases, the advantages make it worth the effort, but I mean, speaking in terms of "good practice", is it?
- 打字需要很长时间,这真的值得付出努力吗?通常来说,一般来说。在某些情况下,优点使它值得付出努力,但我的意思是,就“良好实践”而言,是吗?
Answer:
回答:
Why did I choose the answer with less votes? I was actually very close to choosing veefu's answer; however my personal opinion (which is apparently controversial), is that the answer over egged the pudding.
为什么我选择了票数较少的答案?我实际上非常接近选择veefu 的答案;然而,我个人的意见(这显然是有争议的)是,答案超过了布丁。
The answer I chose, on the other hand, seems to argue both sides; I think getters and setters areevil if used excessively (by that I mean, when it's not necessary and would break the business model), but why shouldn't we have a function called GetBalance()
?
另一方面,我选择的答案似乎对双方都有争议;我认为如果过度使用getter 和 setter是邪恶的(我的意思是,当它没有必要并且会破坏商业模式时),但为什么我们不应该有一个名为 的函数GetBalance()
?
Surely this would be far more versatile than PrintBalance()
; what if I wanted to show it to the user in another way than as the class wanted me to? Now, in some sense GetBalance()
may not be relevant enough to argue that "getters and setters are good" because it doesn't (or maybe, shouldn't) have an accompanying setter, and speaking of which, a function called SetBalance(float f)
could be bad (in my opinion) because it would imply to the implementer of the function that the account must be manipulated out side of the class, which is not a good thing.
当然,这比PrintBalance()
; 如果我想以不同于班级希望我的方式向用户展示它怎么办?现在,从某种意义上说,GetBalance()
可能不足以争论“getter 和 setter 是好的”,因为它没有(或者可能不应该)有一个伴随的 setter,说到这里,一个被调用的函数SetBalance(float f)
可能是坏的(在我看来)因为这会暗示函数的实现者必须在类之外操作帐户,这不是一件好事。
采纳答案by mfazekas
I'd argue that providing accessors are more important in C++ than in C#.
我认为在 C++ 中提供访问器比在 C# 中更重要。
C++ has no builtin support for properties. In C# you can change a public field to a property mostly without changing the user code. In C++ this is harder.
C++ 没有对属性的内置支持。在 C# 中,您可以将公共字段更改为属性,而无需更改用户代码。在 C++ 中,这更难。
For less typing you can implement trivial setters/getters as inline methods:
为了减少输入,您可以将简单的 setter/getter 实现为内联方法:
class Foo
{
public:
const std::string& bar() const { return _bar; }
void bar(const std::string& bar) { _bar = bar; }
private:
std::string _bar;
};
And don't forget that getters and setters are somewhat evil.
并且不要忘记getter 和 setter 有点邪恶。
回答by Daniel Earwicker
In your example:
在你的例子中:
class Foo
{
public:
const std::string GetBar(); // Should this be const, not sure?
You probably mean this:
你可能是这个意思:
std::string GetBar() const;
Putting the const
at the end means "This function doesn't modify the Foo instance it is called on", so in a way it marks it as a pure getter.
把 放在const
最后意味着“这个函数不会修改它被调用的 Foo 实例”,所以在某种程度上它将它标记为纯 getter。
Pure getters occur frequently in C++. An example in std::ostringstream
is the str()
function. The Standard library often follows a pattern of using the same function name for a pair of getter/setter functions - str
being an example again.
纯吸气剂在 C++ 中经常出现。一个例子std::ostringstream
是str()
函数。标准库通常遵循对一对 getter/setter 函数使用相同函数名称的模式 -str
再次作为示例。
As to whether it's too much work to type out, and is it worth it - that seems an odd question! If you need to give clients access to some information, provide a getter. If you don't, then don't.
至于打字是否工作量太大,是否值得——这似乎是一个奇怪的问题!如果您需要让客户访问某些信息,请提供一个 getter。如果你不这样做,那就不要。
回答by Otávio Décio
If you are developing COM components then yes, it is verypopular.
如果您正在开发 COM 组件,那么是的,它非常流行。
回答by peterchen
[edit] It seems I need to emphasize that setters need to validate parameters and enforce invariants, so they are usually not as simple as they are here. [/edit]
[编辑] 看来我需要强调一下,setter 需要验证参数并强制执行不变量,所以它们通常不像这里那么简单。[/编辑]
Not with all, because fo the extra typing. I tend to use them much more often now that Visual Assist gives me "encapsulate field".
不是全部,因为额外的打字。我倾向于更频繁地使用它们,因为 Visual Assist 为我提供了“封装字段”。
The legwork is not more if you implement just the default setters / getters inline in the class declaration (which I tend to do - more complex setters move to the body, though).
如果您只在类声明中内联实现默认的 setter/getter(我倾向于这样做 - 但是更复杂的 setter 移动到主体中),那么跑腿的工作就不会更多。
Some notes:
一些注意事项:
constness:Yes, the getter should be const. It is no use to make the return value const, though, if you return by value. For potentially complex return values you might want to use const & though:
constness :是的,getter 应该是 const。但是,如果按值返回,则将返回值设为 const 是没有用的。对于可能复杂的返回值,您可能想要使用 const & 虽然:
std::string const & GetBar() const { return bar; }
Setter chaining:Many developers like to modify the setter as such:
Setter 链接:许多开发人员喜欢这样修改 setter:
Foo & SetBar(std::string const & bar) { this->bar = bar; return *this; }
Which allows calling multiple setters as such:
这允许像这样调用多个 setter:
Foo foo;
foo.SetBar("Hello").SetBaz("world!");
It's not universally accepted as a good thing, though.
不过,它并没有被普遍接受为一件好事。
__declspec(property): Visual C++ provides this non-standard extension so that callers can use property syntax again. This increases legwork in the class a bit, but makes caller code much friendlier looking.
__declspec(property):Visual C++ 提供此非标准扩展,以便调用者可以再次使用属性语法。这会稍微增加班级的工作量,但使调用者代码看起来更友好。
So, in conclusion, there's a little bit of more legwork, but a handful of decisions to make in C++. Typical ;)
因此,总而言之,还有更多的跑腿工作,但需要在 C++ 中做出一些决定。典型的 ;)
回答by user88637
Yes , get and set are popular in the c++ world.
是的, get 和 set 在 C++ 世界中很流行。
回答by veefu
At the risk of being argumentative, I'll back an opposing point of view I first encountered while reading "Holub on Patterns". It was a point of view that was very challenging, but made sense to me upon reflection:
冒着争论的风险,我将支持我在阅读“Holub on Patterns”时首次遇到的相反观点。这是一个非常具有挑战性的观点,但经过反思对我来说是有意义的:
Getters and Setters are Evil
Getter 和 Setter 是邪恶的
Use of getters and setters is in opposition to the fundamentals of object oriented design: Data abstraction and encapsulation. Overuse of getters and setters will make your code less agile and maintainable in the long run. They ultimately expose the underlying implementation of your class, locking implementation details into the interface of the class.
getter 和 setter 的使用与面向对象设计的基本原则背道而驰:数据抽象和封装。从长远来看,过度使用 getter 和 setter 会降低您的代码的敏捷性和可维护性。它们最终公开类的底层实现,将实现细节锁定到类的接口中。
Imagine your 'std::string Foo::bar' field needs to change from a std::string to another string class, that, say, is better optimized or supports a different character-set. You'll need to change the private data field, the getter, the setter, and all the client code of this class that calls these getters and setters.
想象一下您的 'std::string Foo::bar' 字段需要从 std::string 更改为另一个字符串类,也就是说,更好地优化或支持不同的字符集。您需要更改私有数据字段、getter、setter 以及调用这些 getter 和 setter 的此类的所有客户端代码。
Rather than design your classes to "provide data" and "receive data", design them to "perform operations" or "providide services". Ask yourself why you're writing a "GetBar" function. What are you doing with that data? Perhaps you're displaying that data on or doing some processing on it. Is this process better exposed as a method of Foo?
与其将类设计为“提供数据”和“接收数据”,不如将它们设计为“执行操作”或“提供服务”。问问自己为什么要编写“GetBar”函数。你用这些数据做什么?也许您正在显示该数据或对其进行一些处理。这个过程是否更好地暴露为 Foo 的方法?
This not to say that getters and setters don't have their purpose. In C# I believe the fundamental reason for their use is to interface with the Visual Studio GUI-design IDE, but if you find yourself writing them in C++, it's probably best to take a step back, look at your design, and see if something is missing.
这并不是说 getter 和 setter 没有目的。在 C# 中,我相信使用它们的根本原因是与 Visual Studio GUI 设计 IDE 交互,但是如果您发现自己用 C++ 编写它们,最好退后一步,看看您的设计,看看是否有什么不见了。
I'll try to mock-up an example to illustrate.
我会尝试模拟一个例子来说明。
// A class that represents a user's bank account
class Account {
private:
int balance_; // in cents, lets say
public:
const int& GetBalance() { return balance_; }
void SetBalance(int b) { balance_ = b; }
};
class Deposit {
private:
int ammount_;
public:
const int& GetAmount() { return ammount_; }
void SetAmmount(int a) { _balance = a; }
};
void DoStuffWithAccount () {
Account a;
// print account balance
int balance = a.GetBalance();
std::cout << balance;
// deposit some money into account
Deposit d(10000);
a.SetBalance( a.GetBalance() + d.GetValue());
}
It doesn't take very long to see that this is very poorly designed.
很快就会发现这是非常糟糕的设计。
- Integers are an awful currency datatype
- A Deposit should be a function of the Account
- 整数是一种糟糕的货币数据类型
- 存款应该是账户的一项功能
The getters and setters make it more difficult to fix the problems, since the client code DoStuffWithAccount is now bound to the data-type we used to implement the account balance.
getter 和 setter 使解决问题变得更加困难,因为客户端代码 DoStuffWithAccount 现在绑定到我们用来实现帐户余额的数据类型。
So, lets make a pass on this code and see what we can improve
所以,让我们通过这段代码,看看我们可以改进什么
// A class that represents a user's bank account
class Account {
private:
float balance_;
public:
void Deposit(float b) { balance_ += b; }
void Withdraw(float w) { balance_ -= w; }
void DisplayDeposit(std::ostream &o) { o << balance_; }
};
void DoStuffWithAccount () {
Account a;
// print account balance
a.DisplayBalance(std::cout);
// deposit some money into account
float depositAmt = 1000.00;
a.Deposit(depositAmt);
a.DisplayBalance(std::cout);
}
The 'float' is a step in the right direction. Granted, you could have changed the internal type to 'float' and still supported the getter/setter idiom:
“浮动”是朝着正确方向迈出的一步。当然,您可以将内部类型更改为 'float' 并且仍然支持 getter/setter 习惯用法:
class Account {
private:
// int balance_; // old implementation
float balance_;
public:
// support the old interface
const int& GetBalance() { return (int) balance_; }
void SetBalance(int b) { balance_ = b; }
// provide a new interface for the float type
const float& GetBalance() { return balance_; } // not legal! how to expose getter for float as well as int??
void SetBalance(float b) { balance_ = b; }
};
but it doesn't take long to realize that the getter/setter arrangement is doubling your workload and complicating matters as you need to support both the code that used ints and the new code that will use floats. The Deposit function makes it a bit easier to expand the range of types for depositing.
但是很快就会意识到 getter/setter 安排使您的工作量加倍并使事情复杂化,因为您需要同时支持使用整数的代码和将使用浮点数的新代码。存款功能可以更轻松地扩展存款类型范围。
An Account-like class is probably not the best example, since "getting" the account balance is a natural operation for an Account. The overall point, though, is that you must be careful with getters and setters. Do not get into the habit of writing getters and setters for every data-member. It is quite easy to expose and lock yourself into an implementation if you are not careful.
类 Account 类可能不是最好的例子,因为“获取”帐户余额是 Account 的自然操作。不过,总体而言,您必须小心使用 getter 和 setter。不要养成为每个数据成员编写 getter 和 setter 的习惯。如果您不小心,很容易暴露并锁定自己的实现。
回答by Greg Domjan
get and set are a pain inflicted upon people if you have to use them in any language.
如果您必须在任何语言中使用 get 和 set 对人们造成的痛苦。
Eiffel has it alot better where all that differs is the amount of information you have to provide to get the answer - a function with 0 parms is the same as accessing a member variable, and you can change freely between them.
Eiffel 有很多更好的地方,不同之处在于您必须提供以获得答案的信息量 - 具有 0 parms 的函数与访问成员变量相同,您可以在它们之间自由更改。
When you control both sides of an interface the definition of the interface doesn't seem like such a big issue. However when you want to change implementation details and it inflicts the recompilation of client code as is the common case in C++ you wish to be able to minimise this as much as possible. As such pImpland get/set would get used more in public APIs to avoid such damage.
当您控制接口的两侧时,接口的定义似乎不是什么大问题。但是,当您想要更改实现细节并导致重新编译客户端代码时,就像 C++ 中的常见情况一样,您希望能够尽可能地减少这种情况。因此pImpl和 get/set 将在公共 API 中得到更多使用,以避免此类损坏。
回答by J.W.
The compiler will emit set_ and get_ if you define a property, so it's really just save some typing.
如果您定义一个属性,编译器将发出 set_ 和 get_,因此它实际上只是节省了一些输入。
This has been an interesting discussion. This is something from my favorite book "CLR via C#".
这是一个有趣的讨论。这是我最喜欢的书“CLR via C#”中的内容。
Here is what I quoted.
这是我引用的内容。
Personally, I don't like properties and I wish that they were not supported in the Microsoftm.NET Framework and its programming languages. The reason is because properties look like fields but they are methods. This has been known to cause a phenomenal amount of confu-sion. When a programmer sees code that appears to be accessing a field, there are many assumptions that the programmer makes that may not be true for a property. For example,
- A property may be read-only or write-only; field access is always
readable and writable. If you define
a property, it is best to offer both
get and set accessor methods.A property method may throw an exception; field access never throws
an exception.A property cannot be passed as an out or ref parameter to a method; a field can.
A property method can take a long time to execute; field access always
completes imme- diately. A common
reason to use properties is to
perform thread synchronization, which can stop the thread forever, and
therefore, a property should not be
used if thread synchro- nization is
required. In that situation, a method is preferred. Also, if your class can be accessed remotely (for example,
your class is derived from
System.MashalByRefObject), calling
the property method will be very
slow, and therefore, a method is
preferred to a property. In my
opinion, classes derived from
MarshalByRefObject should never use
properties.If called multiple times in a row, a property method may return
a different value each time; a
field returns the same value each
time. The System.DateTime class has a read- only Now property that returns
the current date and time. Each time you query this property, it will
return a different value. This is a
mistake, and Microsoft wishes that
they could fix the class by making
Now a method instead of a property.A property method may cause observable side effects; field access never does. In other words, a user of a type should be able to set various
properties defined by a type in any
order he or she chooses without
noticing any different behavior in
the type.- A property method may require additional memory or return a
reference to something that is not
actually part of the object's state, so modifying the returned object has
no effect on the original object;
querying a field always returns a
reference to an object that is
guaranteed to be part of the original object's state. Working with a
property that returns a copy can be
very confusing to developers, and
this characteristic is frequently not documented.
就我个人而言,我不喜欢属性,我希望 Microsoftm.NET Framework 及其编程语言不支持它们。原因是因为属性看起来像字段,但它们是方法。众所周知,这会导致大量的混乱。当程序员看到似乎正在访问字段的代码时,程序员会做出许多假设,但对于属性可能并不正确。例如,
- 属性可以是只读的或只写的;字段访问始终是
可读和可写的。如果定义
属性,最好同时提供
get 和 set 访问器方法。属性方法可能会抛出异常;字段访问永远不会抛出
异常。属性不能作为 out 或 ref 参数传递给方法;一个字段可以。
一个属性方法可能需要很长时间才能执行;现场访问总是
立即完成。
使用属性的一个常见原因是
执行线程同步,这可以永远停止线程,
因此,
如果需要线程同步,则不应使用属性
。在这种情况下,首选一种方法。此外,如果您的类可以远程访问(例如,
您的类是从
System.MashalByRefObject派生的),则调用
属性方法将非常
慢,因此,方法
优先于属性。在我
看来,从
MarshalByRefObject派生的类不应该使用
特性。如果连续多次调用,一个属性方法可能
每次都返回不同的值;一个
字段每次返回相同的值
。System.DateTime 类具有返回
当前日期和时间的只读 Now 属性。每次查询此属性时,它都会
返回不同的值。这是一个
错误,微软希望
他们可以通过使
Now 成为一个方法而不是一个属性来修复这个类。一个属性方法可能会导致可观察到的副作用;现场访问从来没有。换句话说,一个类型的用户应该能够以 他或她选择的
任何
顺序设置由一个类型定义的各种属性,而不会
注意到
该类型中的任何不同行为。- 一个属性方法可能需要额外的内存,或者返回
对
实际上不属于对象状态的某些东西的引用,因此修改返回的对象
对原始对象没有影响;
查询一个字段总是返回一个
对象的引用,该对象
保证是原始对象状态的一部分。使用
返回副本的属性可能
会让开发人员感到非常困惑,而且
这个特性通常没有记录。
回答by jalf
There is no really strict convention on this, like there is in C# or Java. Many C++ programmers would just make the variable public an save themselves the trouble.
对此没有真正严格的约定,就像在 C# 或 Java 中那样。许多 C++ 程序员只会将变量设为 public 以省去麻烦。
As other answers have said, you shouldn't often need set, and to some extent, get methods.
正如其他答案所说,您不应该经常需要 set 方法,并且在某种程度上需要 get 方法。
But if and when you do make them, there's no need to type more than necessary:
但是,如果您确实制作了它们,则无需输入更多内容:
class Foo
{
public:
std::string Bar() const { return bar; }
void Bar(const std::string& bar) { this->bar = bar; }
private:
std::string bar;
};
Declaring the functions inline in the class saves typing, and hints to the compiler that you'd like the functions inlined. And it's not much more typing than the C# equivalents. One thing to note is that I removed the get/set prefixes. Instead, we just have two Bar() overloads. That's fairly common in C++ (after all, if it doesn't take any arguments, we know it's the getter, and if it takes an argument, it's the setter. We don't need the name to tell us that), and it saves a bit more typing.
在类中声明内联函数可以节省输入,并向编译器提示您希望内联函数。它并不比 C# 等价物多得多。需要注意的一件事是我删除了 get/set 前缀。相反,我们只有两个 Bar() 重载。这在 C++ 中相当普遍(毕竟,如果它不接受任何参数,我们知道它是 getter,如果它接受一个参数,它就是 setter。我们不需要名称来告诉我们这一点),并且它节省了更多的打字时间。
回答by dmckee --- ex-moderator kitten
Getting and setting data members qua data members: Bad.
Getting and setting elements of the abstraction: Good.
获取和设置数据成员作为数据成员:Bad。
获取和设置抽象元素:Good。