6

Effective C++ 的第 23 条规定:Prefer non-member non-friend functions to member functions。

该项目的全部目的是鼓励封装,以及包的灵活性和功能可扩展性,但我的问题是,在接受这个建议时你走了多远?

例如,您可以拥有您的类、您的私有数据成员,然后通过将公共函数减少为仅用于您的私有数据成员的访问器和/或修改器来采取极简方法。然后,每个其他函数都可以是非成员函数。

但是,您是否愿意在可能牺牲代码清晰度的情况下增加封装,访问器和修改器遍布各处?线画在哪里?

4

5 回答 5

9

首先,不是每个人都同意这个建议。除了 Meyers(编辑:Herb Sutter )之外,我认为我没有见过任何人给出这个建议,而且我只看到它是在 C++ 的上下文中给出的。例如,在 Java 或 C# 中创建“非成员非友元函数”实际上是不可能的,因为 Java 和 C# 没有自由函数,而 Ruby 开发人员(例如)更喜欢有意创建成员函数的“人性化接口”做同样的事情非成员可以,只是为了让这些函数的调用者生活更轻松。

即使您确实接受了 Meyers 的建议,您应该更喜欢非成员非朋友函数而不是成员函数(我认为这是一个很好的建议,它确实帮助我更好地应用封装,以考虑封装一个类的实现,甚至从它的成员功能),这只是一个需要考虑的设计轴。

面向对象设计的关键概念是对象做某事。一个对象不仅仅是其他代码用来处理的一袋 setter 和 getter。相反,它应该附加行为——也就是说,它应该有做事的方法——并且它应该封装它如何做这些事情的细节。如果您遵循这种面向 OO 的方法,那么将 Meyers 的建议发挥到极致会损害封装而不是帮助封装:您最终会通过 getter 和 setter 公开所有类的内部实现变量,而不是隐藏它们,以便只有类的方法(代表类负责做事的代码,这是你有一个类开始的唯一原因)可以得到它。

因此,要回答您对迈耶斯的建议采取多远的问题:如果可以使用类的公共接口将函数合理地实现为非友元非成员函数,则不要将函数不必要地转换为成员函数,但不要损坏类的公共接口并通过公开实现来违反其封装只是为了避免使某些东西成为成员。并确保在封装与其他关注点和其他方法之间取得平衡(包括,如果您的团队决定走这条路,完整的人性化界面的优缺点)。

于 2009-09-29T02:48:52.020 回答
3

退后一步,考虑一下课程的目的它在做什么?它必须确保哪些类不变量以最佳方式完成一项工作?子类化和覆盖在类的目的中扮演什么角色?

将所有内容都放在访问器和修改器方面绝对不合适:这几乎会脱离作为 OOP 根源的状态和行为的结合,或者掩盖在没有合理框架下获取或设置属性的行为这种“假装”的变异器和访问器的面纱。

只有访问器和修改器的类是一种特殊情况——可能比传统的 C 类提高了一步,struct因为它能够保留一些不变量,但“几乎没有”;-)。

一个好的 OOP 设计中的大多数类都会有行为——就像我喜欢泛型编程一样,使用 C++ 的一个原因是它混合了多种范式,其中 OOP 不能被删除!-)

于 2009-09-29T02:47:14.113 回答
2

实际上,仅向您的类的私有变量提供访问器和修改器实际上并不是极简主义(或者在某种意义上可能是极简主义,但不是“最相关”意义上的),因为您现在正在向世界呈现更通用的界面。封装的想法是你的类的接口应该尽可能地受到限制,同时允许客户端代码完成工作。

遵循这种方法使得将来更容易更改底层实现,这首先是封装的重点。

于 2009-09-29T02:47:27.200 回答
0

一般来说,访问器和修改器背后的想法是需要以某种方式保护变量。如果变量包含应该仅由一个实体更新的敏感信息,则可以将该检查包含在您的 mutator 中。一个简单的事实是,大多数访问器和修改器只是一种形式(以至于 C# 现在具有自动属性)并且没有必要。底线是,用你的判断。如果它需要限制访问,则添加一个 mutator。如果谁获取/设置变量无关紧要,则不需要访问器和修改器。

于 2009-09-29T02:34:22.307 回答
0

研究如何将事物打包成合适大小的单元是一门主观的艺术。

我与非会员非朋友的问题之一是,如果内部结构的变化需要添加新的公共接口以支持现有的非会员,或者现在非会员被承认为朋友,那么你就是显示出比以前设计的更紧密的联系。现在进行任何更改都可能变得昂贵。

虽然可以说在逻辑层面上可以将非成员函数与类打包并构成类的接口,但如果方法的位置发生变化,开发人员将需要进行一些代码更改,因此实现界面在使用中不是,errr,透明的。

关于 Eiffel 的其中一个优点是,没有参数的方法的访问方式与变量相同,因此这些元素之间的更改是透明的。

于 2009-09-29T03:12:32.837 回答