《Effective C++》学习笔记(条款23:宁以非成员非友元函数替换成员函数)

最近开始看《Effective C++》,为了方便以后回顾,特意做了笔记。若本人对书中的知识点理解有误的话,望请指正!!!

假设用一个 class 来表示网页浏览器,这样的 class 中有清除缓存、清除历史纪录以及清除 cookies 的函数:

class WebBrowser{
public:
    void clearCache();
    void clearHistory();
    void removeCookies();
    //把调用上述的三个函数的操作封装到一个函数内
    void clearEverything(){
        clearCache();
        clearHistory();
        removeCookies();
    }
  	...
};

许多用户会想把清除缓存、清除历史纪录以及清除cookies的动作封装到一个函数内,所以 WebBrowser 提供了 clearEverything() 函数。当然,这一个函数也可用非成员函数实现:

void cleanBrowser(WebBrowser& wb){
    wb.clearCache();
    wb.clearHistory();
    wb.removeCookies();
}

我们有两种选择,哪种更好呢?

面向对象守则要求数据以及操作数据的函数应该封装在 class 内,那么成员函数是更好的选择?这是错误的,面向对象守则要求数据应该尽可能被封装,然而成员函数 clearEverything()带来的封装性比非成员函数 cleanBrowser() 低。此外,提供非成员函数 WebBrowser 相关机能有较大的包装弹性(packaging flexibility),而这导致较低的编译相依度,增加 WebBrowser 的可延伸性。

条款22说过,成员变量应该声明为 private ,不然它们就毫无封装性,而能够访问 private 成员变量的函数只有 class 的成员函数和友元函数。如果你要在一个成员函数(它不止可以访问 class 内的 private 数据、也可以调用 private 函数、enum、typedef 等)和一个非成员函数(它无法访问上述任何东西)之间做抉择,且两者提供相同机能,那么选择较大封装性的 非成员函数 是最好的。

在这一点上有两件事情需要注意:

  • 这个论述只适用于非成员非友元函数。友元函数对 class 内的 private 成员的访问权限和成员函数相同,因此两者对封装的冲击力度也相同。从封装角度看,这里的选择关键并不在成员函数和非成员函数之间,而是在成员函数和非成员非友元函数之间。(封装并非唯一考虑,条款24解释当我们考虑隐式类型转换,应该在成员函数和非成员函数之间抉择)
  • 以上并不是说这个函数就不能在别的类里。例如我们可以写一个工具类(utility class),然后把 cleanBrowser() 作为它的一个静态成员函数,只要这个函数不在 WebBrowser 里就不会影响其 private 成员的封装。

在C++中,比较自然的做法是让 cleanBrowser() 成为一个非成员函数并且位于 WebBrowser 所在的同一个命名空间内:

namespace WebBrowserStuff{
    class WebBrowser{...};
    void cleanBrowser(WebBrowser& wb){...}
}

命名空间和类不同,前者可跨越多个源码文件而后者不能。因为像 cleanBrowser()这样的函数是个“提供便利的函数”,如果它不是成员函数也不是友元,就没有对 WebBrowser 的特殊访问权力。

一个像WebBrowser 这样的类可能拥有大量的便利函数,某些与书签有关,某些与打印有关,还有些与cookie的管理有关等,通常用户只对某一些感兴趣。就好像一个只对书签相关便利函数感兴趣的用户与一个cookie相关便利函数发生编译相依关系。分离它们的最直接做法就是将它们分别声明于不同的头文件内:

//webbrowser.h 包含浏览器的核心功能
namespace WebBrowserStuff{
class WebBrowser{...};	//浏览器类
    ...	//核心机能
        //非成员函数
}

//webbrowserbookmarks.h 
namespace WebBrowserStuff{
    ...	//与书签相关的便利函数
}

//webbrowsercookies.h 
namespace WebBrowserStuff{
  	...	//与cookies相关的便利函数
}
//以上头文件的代码全部纳入同一名空间

将所有便利函数放在多个头文件内但隶属于同一个命名空间,意味用户可以轻松拓展这一组便利函数。他们需要做的就是添加更多非成员非友元函数到此命名空间内。如现在要添加与图像相关的便利函数:

//webbrowserimage.h 
namespace WebBrowserStuff{
  	...	//与图像相关的便利函数
}

新函数就像其它旧有的便利函数那样可用且整合为一体。这是类无法提供的一个性质,虽然用户可以使用继承来建立派生类,但派生类无法访问基类中的 private 成员。

Note:

  • 宁可用非成员非友元函数替代成员函数,可以增加封装,包装弹性,功能可扩展性。

条款24:若所有参数皆需类型转换,请为此采用非成员函数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值