类设计与IDE:非成员非朋友功能真的值得吗?

时间:2008-09-25 19:59:16

标签: c++ ide function class-design friend

在(另有)优秀书籍C++ Coding Standards,项目44,标题为“首选写非会员非友好函数”,Sutter和Alexandrescu建议只有真正需要访问成员的函数一个班级本身就是那个班级的成员。所有其他只能使用成员函数编写的操作不应该是该类的一部分。他们应该是非成员和非成员。争论是:

  • 它促进了封装,因为需要访问类的内部的代码较少。
  • 它使编写函数模板变得更容易,因为您不必每次都猜测某个函数是否是成员。
  • 它使班级变小,从而使测试和维护更容易。

虽然我看到了这些论点中的价值,但我发现一个很大的缺点:我的IDE无法帮助我找到这些功能!每当我有某种对象时,我想看到可以使用哪些操作,我不能只输入“pMysteriousObject->”并获得成员函数列表。

保持干净的设计最终会让您的编程生活更轻松。但这实际上会让我更难。

所以我想知道它是否真的值得这么麻烦。 你如何处理?

7 个答案:

答案 0 :(得分:5)

Scott Meyers对Sutter有类似的看法,见here

他还清楚地说明了以下内容:

“基于他对各种类似字符串的类的工作,Jack Reeves观察到一些函数在成为非成员时不会”感觉“正确,即使他们可能是非朋友的非成员一个类的“最佳”接口只能通过平衡许多竞争问题来找到,其中封装程度只有一个。“

如果某个函数是“只是有意义”成为成员函数的东西,那就把它作为一个函数。同样,如果它不是主界面的一部分,并且“只是有意义”成为非成员,那就这样做。

需要注意的是,对于例如operator ==()的重载版本,语法保持不变。所以在这种情况下你没有理由使它成为与该类在同一个地方声明的非成员非朋友浮动函数,除非它真的需要访问私有成员(根据我的经验)很少会)。即使这样,您也可以将operator!=()定义为非成员,并根据operator ==()。

答案 1 :(得分:5)

我认为,在他们之间,Sutter,Alexandrescu和Meyers为C ++的质量做的比其他任何人都做得更多是不错的。

他们问的一个简单问题是:

  

如果效用函数有两个独立的类作为参数,哪个类应该“拥有”成员函数?

另一个问题是,您只能添加有关您所控制的课程的成员函数。您为std :: string编写的任何辅助函数都必须是非成员,因为您无法重新打开类定义。

对于这两个示例,您的IDE将提供不完整的信息,您将不得不使用“旧时尚方式”。

鉴于世界上最有影响力的C ++专家认为带有类参数的非成员函数是类接口的一部分,这对于IDE来说更是一个问题而不是编码风格。

您的IDE可能会在一两个版本中发生变化,您甚至可以让它们添加此功能。如果你改变你的编码风格以适应今天的IDE,你可能会发现你将来会遇到更大的问题,而且代码是无法使用的/不可维护的。

答案 2 :(得分:2)

我不得不在这个问题上与Sutter和Alexandrescu不同意。我认为如果函数foo()的行为属于类Bar的职责范围,那么foo()应该是bar()的一部分。

foo()不需要直接访问Bar的成员数据这一事实并不意味着它在概念上不是Bar的一部分。它也可能意味着代码是很好的因素。通过其他成员函数执行所有行为的成员函数并不罕见,我不明白为什么它应该是。

我完全同意外围相关的功能应该成为班级的一部分,但如果某些事情是班级职责的核心,那么无论是否成员,都没有理由不这样做它直接与成员数据混在一起。

至于这些具体要点:

  

它促进了封装,因为需要访问类的内部的代码较少。

实际上,直接访问内部的功能越少越好。这意味着让成员函数尽可能多地通过其他成员函数是一件好事。将完善的函数拆分出来只会让你有一个半类,这需要一堆外部函数才有用。将精心设计的函数从类中拉出来似乎也阻碍了编写良好因素的函数。

  

它使编写函数模板变得更容易,因为您不必每次都猜测某个函数是否是成员。

我根本不明白这一点。如果从类中提取大量函数,则会对函数模板施加更多责任。他们被迫假设他们的类模板参数提供了甚至更少的功能,除非我们假设从他们的类中提取的大多数函数将被转换为模板(呃)。 / p>

  

它使课程变小,从而使测试和维护变得更容易。

嗯,当然。它还创建了许多额外的外部函数来进行测试和维护。我没有看到它的价值。

答案 3 :(得分:1)

外部函数不应该是接口的一部分。从理论上讲,您的类应该只包含数据并公开接口以实现其目的而不是功利性功能。将实用程序函数添加到接口只会增加类代码库并使其不易维护。我目前维持一个有大约50种公共方法的课程,这只是疯了。

现在,实际上,我同意这不容易执行。通常,在您的类中添加另一个方法通常更容易,如果您使用的IDE可以简单地将新方法添加到现有类中,那就更多了。

为了保持我的类简单并且仍然能够集中外部函数,我经常使用适用于我的类的实用程序类,甚至名称空间。 我首先创建将包装我的数据并公开最简单的接口的类。然后,我为每个与该类有关的任务创建一个新类。

示例:创建一个Point类,然后添加一个PointDrawer类将其绘制为位图,PointSerializer将其保存,等等。

答案 4 :(得分:0)

如果你给他们一个共同的前缀,那么如果你输入

,你的IDE可能会有所帮助
::prefix

namespace::prefix

答案 5 :(得分:0)

在许多OOP语言中,非朋友非类方法是居住在与任何事物无关的孤儿院的三等公民。当我写一个方法时,我喜欢挑选好父母 - 一个合适的课程 - 他们有最好的机会感受到欢迎和帮助。

答案 6 :(得分:-1)

我原本以为IDE实际上是在帮助你。

IDE 隐藏了列表中的受保护的功能,因为 public 无法使用公共

如果您已进入课程范围并输入 this-> ,则受保护的功能将显示在列表中。