zoukankan      html  css  js  c++  java
  • effective C++ 条款 23:宁以nonmember、nonfriend替换member函数

    有个class来表示网页浏览器:

    class WebBrowser
    {
    public:
        void clearChache();
        void clearHistory();
        void removeCookies();
    protected:
    private:
    };

    许多用户会想一整个执行所有这些动作,因此WebBrowser也提供这样一个函数:clearEverything

    class WebBrowser
    {
    public:
        void clearChache();
        void clearHistory();
        void removeCookies();
        void clearEverything();
    protected:
    private:
    };

    当然也可以由一个non-member函数调用适当的member函数而提供出来:

    void clearBrowser(WebBrowser wb)
    {
        wb.clearChache();
        wb.clearHistory();
        wb.removeCookies();
    }

    哪一个比较好呢?

    考虑封装性:

    越多东西被封装,我们改变那些东西的能力也就越大。

    对象内的数据。越少代码看到它(访问它),越多的数据可被封装,也就越能自由地改变对象数据,例如改变成员变量的数量,类型等等。如何测量有多少代码可以看到某一块数据呢?计算能够访问它的函数数量来粗糙的测量,越多函数访问它,数据的封装性就越低。

    成员变量应该是private,能够访问private成员变量的函数只有class的member函数和friend函数。如果要在一个member函数(不只可以访问private数据,还可以取用private函数、enums、typedefs等等)和一个non-member函数(无法访问以上任何东西)之间作抉择,两者提供相同的机能,那么导致较大封装性的是non-member non-friend函数,因为它并不增加“能够访问class内之private成分”的函数数量。

    这里只适用于non-member non-friend函数。friend函数对class private成员的访问权力和member函数相同,因此两者对封装的冲击也相同。

    只因在意封装而让函数“成为class 的non-member”,并不意味着它“不可以是另一个class的member”。假如我们可以另clearBrowser成为某工具类(utility class)的一个static member函数。

    在c++中,比较自然的做法是让clearBrowser成为一个non-member函数并且位于WebBrowser所在的同一个namespace(命名空间)内:

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

    像clearBrowser这样的函数是个“提供便利的函数”。一个像WebBrowser这样的class可能拥有大量的便利函数,某些与书签有关,某些与打印有关,某些与cookie的管理有关…,通常,大多数客户只对其中某些感兴趣。没有道理一个只对书签感兴趣的客户却与一个cookie相关便利函数发生编译相依关系。分离他们最直接的方法是将他们放入不同的头文件:

    //头文件webbrowser.h这一头文件针对class WebBrowser自身以及WebBrowser核心机能。

    namespace WebBrowserStuff{
        void clearBrowser(WebBrowser wb);
        ...//WebBrowser核心机能,几乎所有客户都需要的non-member函数。
    }

    //头文件“webbrowserbookmarks.h”

    namespace WebBrowserStuff{
        class WebBrowser{...};
        ...//与书签相关的便利函数
    }

    //头文件“webbrowsercookies.h”

    namespace WebBrowserStuff{
        class WebBrowser{...};
        ...//与cookie相关的便利函数
    }

    c++标准程序库正是这样的组织方式。数十个头文件,每个头文件声明std的某些机能。如果只想使用vector不用#include <memory>;如果不想使用list也不需要#include <list>.这允许客户只对他们所用的那一小部分系统形成编译相依。这种切割机能并不适合class成员函数,因为class 必须整体定义,不能被分割为片段。namespace可以跨越多个源码文件而class不能

    将所有便利函数放在多个头文件中但隶属同一个命名空间,意味着客户可以轻松扩展这一组便利函数。他们所要做的就是添加更多non-member non-friend函数到此命名空间内。例如:如果客户想写些与影像下载相关的便利函数,只要在WebBrowserStuff命名空间内建立一个头文件,内含那些函数的声明即可。新函数就像其他旧函数一样可用且整合为一体。这是class无法提供的另一个性质,因为class定义对客户是不能扩展的。

    拿non-member non-friend函数替换member函数。可以增加封装性包裹弹性(packaging flexibility)、和机能扩充性

  • 相关阅读:
    Swift ARC 自动引用计数
    Swift 值类型和引用类型的内存管理
    Swift 栈和堆
    Swift 命令行输入输出
    在 OC 中调用 Swift 代码
    在 Swift 中调用 OC 代码
    Swift 类型桥接
    Swift 与 C 语言混合编程
    Swift Precondition 预处理
    Swift Assert 断言
  • 原文地址:https://www.cnblogs.com/lidan/p/2326062.html
Copyright © 2011-2022 走看看