获取/设置c ++世界,faux-pas?

时间:2008-12-16 21:03:31

标签: c++ oop

我注意到,通过查看boost / stl,甚至阅读一些顶级c ++专家的着作,get / set不是c ++方式。

有没有人在他们的c ++类设计中使用get / set,并且如果这个范例属于c ++世界,有人可以建议一个经验法则吗?

它显然在Java中非常流行,并且使用属性语法糖来模仿c#。

编辑:

在下面的答案中提供的一个链接中阅读了更多相关信息后,我遇到了至少一个参数,用于保持成员字段的访问者与成员字段的名称相同。也就是说,您可以简单地将成员字段公开为public,而是将其作为类的实例,然后重载()运算符。通过使用set / get,您不仅要强制客户端重新编译,还要实际更改其代码。

不确定我是否喜欢这个想法,对我来说似乎有点太精细了,但更多细节在这里:

C++ Killed the Getter/Setter

12 个答案:

答案 0 :(得分:13)

C ++没有像C#这样的属性。可以在名称中编写带“get”和“set”的方法,但它们不会自动创建属性。那么使用get和set方法是不错的做法呢?

在C ++中使用get和set方法对于访问类属性并不错。 STL和boost(受STL影响)只选择了一种设计 - 为您的课程设计不同的设计是完美的。

在我的工作中,我们确实使用get和set。原因主要在于它可以编写解析器以通过其他接口(ActiveX,.NET,LabVIEW,Python等)自动包装C ++类....当使用Visual Studio的智能(以及其他IDE上的类似技术)时,我发现使用get和set方法可以更轻松地找到我的内容。因此,有时候使用get和set方法是不合适的。

最重要的是为您的库选择代码样式标准并与之保持一致。

答案 1 :(得分:7)

封装是一种OOP概念,它适用于所有OOP语言。公共数据成员将破坏封装。如果你有一个不需要封装的非常简单的对象,这可能没什么问题,但是这些情况是例外情况,一旦你做出决定就很难回去并撤消它。

对于大多数对象,您需要使用getter和setter,但是在编写对象时应始终考虑如何实际使用该对象。 Boost和STL充满了getter和setter,他们只是不使用名称“get”和“set”而是使用“length”,“end”,“reserve”,“capacity”等名称。他们之所以如此不要使用get或set这样的单词,因为这些函数的用途不仅仅是在对象中设置一个值。

你的getter和setter也应该这样做。不是根据对象的工作方式设计界面,而应根据它的使用方式来定义它。

答案 2 :(得分:6)

你绝对可以在C ++中使用访问器。这是a good article提出良好的访问者方案。 A related article还向您展示了一个简单的元访问器助手类,可帮助您轻松定义这些智能访问器。

答案 3 :(得分:5)

通常,get / set方法通过公开内部实现和状态来破坏封装。如果您发现自己在类中的每一个数据上都使用了get / set,那么最好只使它成为一个只有公共数据而没有方法的简单聚合类型。

我并不是真的认为get / set使得更容易做一些事情,例如让你的类线程安全,因为你可以提供的有限同步可以防止所有错误的竞争条件。

答案 4 :(得分:1)

我不知道它是否是推荐的用法,但是我经常在我的C ++类中使用get / set函数,而且我已经编写了二十多年的C ++代码了。我从来没有看过Java或C#,所以我没有从这些语言中习惯。

答案 5 :(得分:1)

我倾向于有吸气剂和制定者,我只是不倾向于将它们称为“getX和”setX“,通常我会做这样的事情,例如:

int x = o->x() // getter
o->setX(5); // setter

我发现将getter简单地称为“属性”的名称只是读得更好。

答案 6 :(得分:1)

我几乎总是使用get / set方法,主要是因为你可以在它们上设置断点并找出数据成员的设置位置(或访问,尽管这种情况不太常见)。此外,您可以在setter例程中添加调试断言(以及getter例程,尽管这不太有用),以确保在设置值时对象处于有效状态。

如果你创建一个子类,它也很有用;有时子类想要进行一些计算,而不仅仅是重新调整值。将getter例程虚拟化然后在子类中覆盖它会使这变得容易。

答案 7 :(得分:1)

这里有点说教......

访问者有两个方面:

  • 使用语言
  • 的语法
  • 传达意图

还有一个经常被忽略的第三个方面,那就是优雅地处理变更。我链接的文章解决了最后一点,但没有告诉你关于其他两个的任何内容。

尝试在您正在使用的语言语法中处理更改主要是一个技术问题,一个可以在网页上一起提供的一些提示,并提供一些代码来支持它。

最难的方面是沟通意图,而这样做的方法就是坚持使用语言的习语。不幸的是,在C ++中,语法在某种程度上妨碍了这一点,因此我们在集合上使用了.size(),在.first和.second上使用了类似的东西。它们都是访问器,但语法会根据实现而改变 - 哎哟。

现在,eJames谈到公众成员打破封装。成员是否公开与封装无关。封装是对象设计和类设计者在他们使用的语言中可用的控件的产物。这是我在“Encapsulation is a Good Thing™”中更深入探讨的内容(此网站不会让我添加链接,但我想这对谷歌来说并不难)。

这给我们留下的是,在C ++中,派生属性必须使用方法调用语法。非衍生字段不必,但如果您愿意,可以选择。如果您确实使用方法调用语法,那么您必须自己编写包装器方法。不难,但它确实增加了行数。我试图展示的是一种使用C ++模板语言来抽象出访问者代码的方法。它并不完全成功,但它确实处理了许多用例。

至于我们是否应该使用访问器,问题是C ++语法强制区分普通成员访问和作为开发人员的方法访问。这很烦人,但我们确实有一些工具可以做些什么。

作为一个库开发人员,我发现总是使用方法调用语法可以帮助我构建更强大的API,因为如果我发现我想用更复杂的东西替换普通成员那么它给了我更多的选项而不是需要相当多的语法。请记住,我可以抽象另一种方式,通过合适地使用强制转换运算符和赋值运算符使“函数”看起来像一个值 - 实际上我可以尝试一下,看看我对它的感受:)

答案 8 :(得分:0)

我的经验是通过C ++和Java,虽然现在我正在使用PHP。我用于PHP和C ++的一般经验法则是:

  1. 如果您需要从类外部读取成员变量但不可写:仅使用getVariableX()。

  2. 如果要允许在类之外更改/读取成员变量,但需要在更改值之前/之后对它们执行其他工作:使用setVariableX()和getVariableX()。

  3. 如果一个成员变量可以从类外部进行更改,而set / get方法只是简单的赋值:只需将变量设为public,因为这就是你用set / gets所做的事情(只是在更混淆的方式)。

  4. 请注意,如果你的get和set方法所做的远不只是简单的获取和设置,那么你应该重命名它们以更准确地描述它们的功能。

答案 9 :(得分:0)

当没有其他选择时,我只使用getter / setter。当我可以的时候,我使用这种模式(不是因为它是一种很好的实践,但在某种意义上说我是这样做的):在真正需要之前,更改属性不会影响对象的行为。例如:

myWnd->Title = "hello"; // not a setter, just a LPCSTR member
myWnd->Title = "world";
myWnd->ShowWindow();    // perhaps updates a WNDCLASS structure
                        // and other complicated things that
                        // the user of the class doesn't want to know

我知道这意味着我必须编写一些人为的私有方法来更新对象的内部状态,但是如果需要这样的努力来隐藏类用户的复杂性,我将不得不做到。

答案 10 :(得分:0)

我将采取一些猜测。

  • C甚至没有getter / setter的可能性,因此习惯使用直接访问成员,就像在结构中一样。习惯停留在C ++中。
  • C / C ++总是偏爱速度,如果旧编译器有可能无法正确内联,则getter / setter会有速度惩罚。

这些都不是令人信服的理由。

答案 11 :(得分:0)

即使c ++不通过模拟它们来支持属性访问器,我们也不仅仅提高可读性或提供封装,但是我们提供控制机制来将值设置为变量或者我们得到变量的计算值。所以这是访问者的最终目的。要实现这些目标语言,必须直接支持访问者。周期。