类设计与IDE:非成员非友情函数真的值得吗?

Car*_*org 4 c++ ide class-design function friend

在(另有)优秀的书籍C++编码标准,第44项,标题为"首选写非成员非朋友函数"中,Sutter和Alexandrescu建议只有真正需要访问类成员的函数才能成为该类成员.所有其他只能使用成员函数编写的操作不应该是该类的一部分.他们应该是非成员和非成员.争论是:

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

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

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

所以我想知道它是否真的值得这么麻烦.你怎么处理那件事呢?

Gre*_*ers 5

Scott Meyers对Sutter有类似的看法,请看这里.

他还明确指出以下内容:

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

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

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


Ric*_*den 5

我认为,在他们之间,Sutter,Alexandrescu和Meyers在C++的质量方面做得比其他任何人都要多,这并不是错的.

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

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

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

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

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

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


Der*_*ark 3

在这一点上我将不得不不同意萨特和亚历山德雷斯库的观点。我认为如果函数的行为属于类的职责foo()范围,那么应该是 的一部分。Barfoo()bar()

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

我完全同意与外围相关的函数不应该类的一部分,但是如果某些东西是类职责的核心,那么它没有理由不应该成为成员,无论它是否直接与成员数据混在一起。

至于具体的几点:

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

事实上,直接访问内部的函数越少越好。这意味着让成员函数通过其他成员函数尽可能多地完成任务是一件好事。将分解良好的函数从类中分离出来只会留下半个类,这需要一堆有用的外部函数。将分解良好的函数从类中取出似乎也会阻碍分解分解良好的函数的编写。

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

我完全不明白这一点。如果您从类中取出一堆函数,那么您就将更多的责任推给了函数模板。他们被迫假设他们的类模板参数提供的功能甚至更少,除非我们假设从他们的类中提取的大多数函数将被转换为模板(呃)。

它使类保持较小,从而更容易测试和维护。

嗯,当然。它还创建了许多额外的外部函数来测试和维护。我看不到这其中的价值。

  • 请注意,C++ 认为这些自由函数仍然是类接口的一部分 - 但我猜这是一个命名问题,需要进行另一场辩论。 (4认同)