在C ++中设置/获取方法

Java程序员和API似乎更喜欢显式的set / get方法。

但是我得到了C ++社区对这种做法不满的印象。 如果是这样,是否有一个特殊的原因(除了更多的代码行)为什么会这样?

另一方面,为什么Java社区选择使用方法而不是直接访问?

谢谢

理想情况下,精心设计的类应该没有太多的获取和设置。 在我看来,太多的获取和集合基本上表明其他人(可能还有许多人)需要我的数据来实现他们的目的。 在那种情况下,为什么这些数据首先属于我? 这违反了封装的基本原则(数据+操作在一个逻辑单元中)。

因此,虽然没有技术限制和(实际上很多)’set’和’get’方法,但我会说如果你想要太多的’get’和’set’,你应该暂停并重新检查你的设计。您的类接口被系统中的太多其他实体使用。

在某些情况下,getter / setter是合适的,但是大量的getter / setter通常表明你的设计无法实现任何更高级别的抽象。

通常,(对于封装而言)更好地为对象展示更高级别的操作,这些操作不会使用户明白实现。

其他一些可能的原因导致它在C ++中不像在Java中那么常见:

  • 标准库不使用它。
  • Bjarne Stroustrup 表示不喜欢它(最后一段):

    我特别不喜欢有很多get和set函数的类。 这通常表明它本来不应该是一个阶级。 它只是一个数据结构。 如果它确实是一个数据结构,那就把它变成一个数据结构。

反对get / set方法的常见理由是,如果你有两个并且它们只是微不足道的return x;x = y; 然后你根本没有封装任何东西; 您也可以将该成员公开,以节省大量的样板代码。

显然有些情况下它们仍然有意义; 如果你需要在它们中做一些特殊的事情,或者你需要使用inheritance,特别是接口。

有一个优点是,如果您实现getter / setter,您可以在以后更改其实现,而无需更改使用它们的代码。 我认为你提到的皱眉是一种YAGNI的事情,如果没有期望以这种方式改变function,那么拥有它们几乎没有什么好处。 在许多情况下,您可以稍后处理更改实现的情况。

我不知道C ++社区对Java社区不屑一顾; 我的印象是,它们在Python等语言中并不常见。

我认为C ++社区对getter和setter不满的原因是C ++提供了更好的选择。 例如:

 template  class DefaultPredicate { public: static bool CheckSetter (T value) { return true; } static void CheckGetter (T value) { } }; template > class Property { public: operator T () { Predicate::CheckGetter (m_storage); return m_storage; } Property  &operator = (T rhs) { if (Predicate::CheckSetter (rhs)) { m_storage = rhs; } return *this; } private: T m_storage; }; 

然后可以像这样使用:

 class Test { public: Property  TestData; Property  MoreTestData; }; int main () { Test test; test.TestData = 42; test.MoreTestData = 24; int value = test.TestData; bool check = test.TestData == test.MoreTestData; } 

请注意,我在属性类中添加了一个谓词参数。 有了这个,我们可以获得创造性,例如,一个属性来保存整数颜色通道值:

 class NoErrorHandler { public: static void SignalError (const char *const error) { } }; class LogError { public: static void SignalError (const char *const error) { std::cout << error << std::endl; } }; class Exception { public: Exception (const char *const message) : m_message (message) { } operator const char *const () { return m_message; } private: const char *const m_message; }; class ThrowError { public: static void SignalError (const char *const error) { throw new Exception (error); } }; template  class RGBValuePredicate : public DefaultPredicate  { public: static bool CheckSetter (int rhs) { bool setter_ok = true; if (rhs < 0 || rhs > 255) { ErrorHandler::SignalError ("RGB value out of range."); setter_ok = false; } return setter_ok; } }; 

它可以像这样使用:

 class Test { public: Property  > RGBValue1; Property  > RGBValue2; Property  > RGBValue3; }; int main () { Test test; try { test.RGBValue1 = 4; test.RGBValue2 = 5; test.RGBValue3 = 6; test.RGBValue1 = 400; test.RGBValue2 = 500; test.RGBValue3 = -6; } catch (Exception *error) { std::cout << "Exception: " << *error << std::endl; } } 

请注意,我也将错误值的处理作为模板参数。

以此为出发点,可以通过多种不同方式进行扩展。

例如,允许属性的存储与值的公共类型不同 - 因此上面的RGBValue可以使用unsigned char进行存储,但使用int接口。

另一个例子是更改谓词,以便它可以改变setter值。 在上面的RGBValue中,这可用于将值钳位到0到25​​5的范围,而不是生成错误。

作为通用语言概念的属性在技术上早于C ++,例如在Smalltalk中,但它们并不是标准的一部分。 当用于开发UI时,Getters和setter是C ++中使用的一个概念,但事实上,在有效的系统语言中开发UI是一个昂贵的主张。 C ++中getter和setter的一般问题是,因为它们不是标准,所以每个人都有不同的标准。

在系统语言中,效率问题很高,然后将变量本身公开变得更容易,尽管有很多文献对这种做法大为赞赏。 通常,您只是在C ++对象实例之间看到比简单项更丰富的信息交换。

你可能会在回答这个问题时获得很多观点,但总的来说,C ++本来就是做C对象的,它使OOP可以访问不知道对象的开发人员。 将虚拟和模板添加到语言中是很困难的,我认为它暂时停滞不前。

Java的不同之处在于,Java最初带来了像垃圾收集这样的领域,因此更容易推广强大的封装理念,即外部实体应该保持其粗略的小爪子脱离类的内部元素。

我承认这是非常多的意见 – 此时我使用C ++进行高度优化的东西,比如3D图形管道 – 我已经必须管理我所有的对象内存,所以我会对根本无用的代码进行简洁的观察存储访问附加function – 也就是说,像MSFT .net ILM这样的运行时的基本性能能力使得这个位置有时难以防御

纯粹是我的2c

在C ++中使用显式的set / get方法并不罕见。 我已经在很多C ++中看到它,不允许直接访问数据成员非常有用。

查看这个问题 ,以解释为什么Java倾向于选择它们,并且C ++的原因是相同的。 简而言之:它允许您更改数据成员的访问方式,而无需强制客户端代码(使用您的代码的代码)重新编译。 它还允许您强制执行特定策略,以了解如何访问数据以及访问数据时要执行的操作。

通过强制使用set / get方法,可以在getter / setter中实现有用的副作用 (例如,当get / set的参数是一个对象时)。

我很惊讶没有人提到Java内省和bean。

使用get … / set …命名约定与内省相结合,允许使用实用程序类进行各种巧妙的诡计。

我个人觉得“public”关键字应该足以触发bean魔法,但我不是Ray Gosling。

我对此的看法是,在C ++中是一个相当无意义的练习。 您正在添加至少六行代码来进行测试和维护,这些代码没有任何用处,并且大部分都会被编译器忽略。 除非您添加更多编码,否则它并不能真正保护您的class级免遭滥用和滥用。

我不认为C ++社区不喜欢使用getter和setter。 他们几乎总是一个好主意。

它与面向对象编程的基础有关 – 将对象的内部隐藏在用户之外。 对象的用户不需要知道(也不应该关心)对象的内部。

它还使您可以控制对象的用户尝试读取/写入时所执行的操作。 实际上,您将接口暴露给对象的用户。 他们必须使用该接口,并控制在调用该接口中的方法时会发生什么 – getter和setter将成为接口的一部分。

它只是在调试时使事情变得更容易。 一个典型的场景是当你的对象以一种奇怪的状态出现时,你正在调试以找出它是如何到达那里的。 你要做的就是在你的getter和setter中设置断点,假设其他一切都很好,你就能看到你的对象如何进入奇怪的状态。 如果您的对象的用户都直接访问其成员,那么确定对象状态更改的时间会变得更加困难(尽管并非不可能)

我认为C ++比Java更需要getter / setter。

在Java中,如果你从裸体字段访问开始,后来你改变主意,你想要getter / setter,那么很容易找到字段的所有用法,并将它们重构为getter / setter。

在C ++中,这并不容易。 语言太复杂,IDE根本无法可靠地做到这一点。

所以在C ++中,你最好在第一次就把它弄好。 在Java中,您可以更具冒险精神。

在java之前有很多获取/设置。 有很多理由使用它们,特别是,如果你必须重新计算…… 值得改变。 因此,第一大优势是,您可以关注价值变化。 但是imho对于总是实现获取和设置是不好的 – 经常获得就足够了。 另一点是,class级变化将直接影响您的客户。 您无法更改成员名称,而无需使用公共成员重构客户端代码。 可以说,你有一个长度的对象,你改变了这个成员名…呃。 使用getter,您只需更改代码,客户端就可以安然入睡。 为隐藏的成员添加gets / Sets当然是无稽之谈。