标签:
条款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)
标签:
原文地址:http://www.cnblogs.com/hansonwang99/p/4941551.html