中国建设银行官网站住房公积金全网搜索关键词查询
想象有个class用来表示网页浏览器。这样的class可能提供的众多函数中,有一些用来清除下载元素高速缓存区、清除访问过的URLs的历史记录、以及移除系统中的所有cookies:
class WebBrowser{
public:void clearCache();void clearHistory();void removeCookies();
};
许多用户会想一整个执行这些动作,因此WebBrowser也提供一个函数:
void clearEverything();
//调用clearCache,clearHistory和removeCookies
这一机能也可由一个non-member函数调用适当的member函数而提供出来:
void clearBrowser(WebBrowser& wb)
{wb.clearCache();wb.clearHistory();wb.removeCookies();
}
那么,哪一个比较好?
面向对象守则要求数据应该尽可能被封装,然而与直观相反地,member函数clearEverything带来的封装性比non-member函数clearBrowser低。此外,提供non-member函数可允许对WebBrowser相关机能有较大的包裹弹性(packaging flexibility),而那最终导致较低的编译相依度,增加WebBrowser的可延伸性。
对于封装,愈多东西被封装,改变哪些东西的能力也就愈大。
对于对象内的数据,愈少代码可以看到数据(也就是可以访问它),愈多的数据可被封装,而我们也就愈能自由地改变对象数据。愈多函数可访问它,数据的封装性就愈低。
若你要在一个member函数和一个non-member,non-friend函数之间做抉择,而且两者提供相同机能,那么,导致较大封装性的是non-member non-friend函数,因为它并不增加“能够访问class内的private成分”的函数数量。这解释了为什么clearBrowser比everyEverything更受欢迎:它导致了WebBrowser class有较大封装性。
但这个论述只适用于non-member non-friend函数。且只因在意封装性而让函数“称为class的non-member”,并不意味着它“不可以是另一个class的member”。
在C++中比较自然的做法是让clearBrowser成为一个non-member函数并且位于WebBrowser所在的同一个namespace(命名空间)内:
namespace WebBrowserStuff{class WebBrowser{};void clearBrowser(WebBrowser& wb);
}
但这不只是为了看起来自然而已,因为想clearBrowser这样的函数是个“提供便利的函数”,若它既不是member也不是friend,就没有对WebBrowser的特殊访问权力,也就不能提供“WebBrowser客户无法以其他方式取得”的机能。
将所有便利函数放在多个头文件内但隶属同一个命名空间,意味客户可以轻松扩展这一组便利函数。他们需要做的就是添加更多non-member non-friend函数到此命名空间内。
例如,若某个WebBrowser客户决定写些与影像下载相关的便利函数,他只需在WebBrowserStuff命名空间内建立一个头文件,内含那些函数的声明即可。新函数就像其他旧有的便利函数那样可用且整合为一体。这是class无法提供的另一个性质,因为class定义式对客户而言是不能扩展的。
总结
宁可拿non-member non-friend函数替换member函数。这样做可以增加封装性、包裹弹性和技能扩充性。