EffectiveC++-条款23:宁以 non-member、non-friend 替换 member函数

一. 内容

  1. 举个例子,当你有个 class 表示浏览器时,有众多功能需要提供,其中可能有清除下载元素的高速缓存区,清除访问过的 URLs,清除系统中所有的 cookies。

    示例代码

    class WebBrowser {
    public:
         void ClearCache(){std::cout<<"clear cache"<<"\n";}
         void ClearHistory(){std::cout<<"clear history"<<"\n";}
         void ClearCookies(){std::cout<<"clear cookies"<<"\n";}
         void ClearEverything() {
            ClearCache();
            ClearHistory();
            ClearCookies();
        }
    };
    inline void ClearWebBrowserEverything(WebBrowser& WebBrowser) {
        WebBrowser.ClearCache();
        WebBrowser.ClearHistory();
        WebBrowser.ClearCookies();
    }
    

    问题来了,如果想要提供给用户清除所有的功能,究竟是使其成为 member 函数,还是 non-member 函数?两者似乎都可以实现功能。

  2. 面向对象守则要求:数据应该和操作数据的那些函数捆绑在一块,这意味着它建议 member 函数是较好的选择。不幸的是,这是对基于对象真实含义的一个误解。面向对象守则要求数据尽可能被封装,而与直观相反的是,non-member 函数带来的封装性要比 member 函数高。此外,提供 non-member 函数可以提供更多的机能上的包裹弹性,而且可以降低编译相依度,增加对象的可延伸性。

  3. 让我们从封装开始讨论。如果某些东西被封装,它就不再可见。愈多东西被封装,愈少人可以看见它们。而愈少人看见,我们就有愈大的弹性去改变它们,因为我们改变仅仅影响到看到的那些人的事物。因此愈多东西被封装,我们改变事物的能力就愈大。这也是我们推崇封装的原因。

  4. 现在考虑对象内的数据,愈多函数可以访问它们,数据的封装性就越低。条款22曾说,成员变量应该是 private,能访问 private 的成员函数就只有 class 的 member 函数和 friend 函数。所以如果 member 函数和 non-member,non-friend 函数可以提供相同的机能,那么能提供较大封装性的应该是后者。

  5. 注意 non-member 函数不意味着它不可以是另一个 class 的 member 函数

  6. non-member 函数在 C++ 中比较自然的做法是让 class 和 non-member 函数在一个 namespace(命名空间)

    namespace WebBrowserStuff {
        class WebBrowser {
        public:
            void ClearCache(){std::cout<<"clear cache"<<"\n";}
            void ClearHistory(){std::cout<<"clear history"<<"\n";}
            void ClearCookies(){std::cout<<"clear cookies"<<"\n";}
        };
        inline void ClearWebBrowserEverything(WebBrowser& WebBrowser) {
            WebBrowser.ClearCache();
            WebBrowser.ClearHistory();
            WebBrowser.ClearCookies();
        }
    }
    

    当然不只是为了自然一些,要知道 namespaces 和 classes 不同,前者可以跨越多个源文件,而后者不能。这很重要,意味着可以在不同的源文件提供这些 non-member 便利函数。

    注意这正是 C++ 标准库的组织方式。标准程序库并不是拥有单一、整体、庞大的 <C++ StandardLibrary> ,内含std命名空间的每一项东西,而是有数十个头文件(<vector>,<algorithm>,<memory>),每一个头文件声明一定的机能,用户只需引用所必要的头文件便可使用对应的功能。

二. 总结

  1. 宁可拿 non-member non-friend函数替换 member 函数。这样做可以增加封装性、包裹弹性(package flexibility)和机能扩展性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值