• EC读书笔记系列之12:条款22、23、24


    条款22 将成员变量声明为private

    记住:

    ★切记将成员变量声明为private。这可赋予客户访问数据的一致性、可细微划分访问控制、允诺约束条件获得保证,并提供class作者以充分的实现弹性。

    ★protected并不比public更具封装性

    条款23 宁以non-member-non-friend替换member函数

    记住:

    ★宁可拿non-member-non-friend函数替换member函数。这样可增加封装性、包裹弹性和机能扩充性。

    -------------------------------------------------------------------------------

    举例:

    class WebBrowser {
        ...
        void clearCache();  //清除缓存
        void clearHistory();//清除历史
        void clearCookies();//清除cookies
        ...
    };

    假设想一次性执行上面三个有关清理的函数,有两种方法:

    方法一:将这个一次性清理工作函数写成member function

    class WebBrowser {
        public:
            ...
            void clearEverything(); //调用上面的三个函数
            ...
    };

    方法二:写成non-member-non-friend函数:

    void clearBrowser( WebBrowser &wb ) {
        
        wb.clearCache();
        wb.clearHistory();
        wb.clearCookies();
    }

    方法二要好一点!!!因为non-member函数将导致较大的封装性,∵其并不能访问class内部的private成分。(因为对于对象内的数据来说,愈少代码可以看到数据,也即访问它,愈多的数据就可被封装,而我们也就愈能自由地改变对象的数据,这不也就是封装性的体现吗!!)

    两件需要注意的事:

    一、上述论述仅适用于no-member-non-friend函数;

    二、因在意封装性而让函数“成为class的non-member”,并不意味着其“不可以是另一个class的member”

    推荐做法

      让clearBrowser成为一个non-member并且位于WebBrowser所在的同一个namespace内:

    namespace WebBrowserStuff {
        class WebBrowser {...};
        void clearBrowser( WebBrowser &wb );
        ...
    }     //注意namespace这里无分号!!!

    注:像上面WebBrowser这样的class可能拥有多种便利函数,如某些与书签有关,某些与打印有关等。可以将这些便利函数的编译相依关系降低:分离他们的直接做法是将书签相关的便利函数声明于一个头文件,将打印相关的便利函数声明于另一个头文件:

    namespace WebBrowserStuff {
    
        class WebBrowser{...};  //核心机能
    }
    
    //头文件"webbrowserbookmark.h"
    namespace WebBrowserStuff {
    
        ... //与书签相关的便利函数
    }
    
    //头文件"webbrowserprint.h"
    namespace WebBrowserStuff {
    
        ... //与打印相关的便利函数
    }

    以此种方式切割机能并不适用于member函数,因为一个class必须整体定义,不能被分割为片段,从这个角度来说也符合本条款的主题。

    条款24 若所有参数皆需类型转换,请为此采用non-member函数

    记住:

    ★若需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么此函数必须是个non-member。

    -------------------------------------------------------------------------------

    举例:有理数类

    class Rational {
        public:
            Rational( int numerator = 0,
                      int denominator = 1 
                    ); //构造函数刻意不为explicit,
                    //这样做是为了int-to-Rational隐式转换
            ...
    };

    现让该有理数类支持乘法运算。现将operator*写为类的member函数:

    class Rational {
        public:
            ...
            const Rational operator*( const Rational &rhs ) const;
    };

    若下面这样用:

    Rational oneEighth( 1, 8 );
    Rational oneHalf( 1, 2 );
    Rational result;
    result = oneHalf*oneEighth;    //用法1:可以
    result = oneHalf*2;             //用法2:可以
    result = 2*oneHalf;             //用法3:错误

    这里的用法2,之所以行得通,是因为这里发生了隐式类型转换,等价于下面这样调用:

      const Rational temp(2);  //建立一个暂时性的Rational对象

      result = oneHalf*temp;  //等价于oneHalf.operator*( temp );

    当然这种做法可行的前提是non-explicit constructor!!!

    仅当参数被列于参数列内,此参数才是隐式类型转换的合格参与者,这是用法2和用法3的区别。

    解决方案:将operator*写成non-member函数,这样便可以使在每一个实参身上执行隐式类型转换!!!

    const Rational operator*( const Rational &lhs,
                              const Rational &rhs
                            ) {
    
        return Rational( lhs.numerator() * rhs.numerator(),
                         rhs.denominator() * rhs.denominator()
                        );
    }
    这样:
    result = oneHalf*2;            
    result = 2*oneHalf;            //也可以通过编译了!!!

    注意:

    member函数的反面是non-member函数,而不是friend函数!!!(因为有太多的C++程序员错误地认为若一个“与某class相关”的函数不该成为一个member,就该是个friend)

  • 相关阅读:
    【漏洞复现】CVE2022–21661 WordPress核心框架WP_Query SQL注入漏洞原理分析与复现
    PAT顶级 1001 Battle Over Cities Hard Version (35 分)(最小生成树)
    Leetcode 1001. 网格照明(map)
    2022牛客寒假算法基础集训营4 ABCDEFGHIJK
    KD Tree 模版
    PAT顶级 1003 Universal Travel Sites (35 分)(DP)
    CCFCSP认证 2021123 登机牌条码(90分)
    Leetcode 956. 最高的广告牌(DP)
    Codeforces Round #774 (Div. 2) C. Factorials and Powers of Two(暴力/dfs/位运算)
    第 46 届 ICPC 国际大学生程序设计竞赛亚洲区域赛(上海)I. Steadily Growing Steam(DP)
  • 原文地址:https://www.cnblogs.com/hansonwang99/p/4941551.html
Copyright © 2020-2023  润新知