条款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 = ,
int denominator =
); //构造函数刻意不为explicit,
//这样做是为了int-to-Rational隐式转换
...
};

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

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

若下面这样用:

Rational oneEighth( ,  );
Rational oneHalf( , );
Rational result;
result = oneHalf*oneEighth;   //用法1:可以
result = oneHalf*; //用法2:可以
result = *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*;
result = *oneHalf; //也可以通过编译了!!!

注意:

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

EC读书笔记系列之12:条款22、23、24的更多相关文章

  1. EC读书笔记系列之7:条款12 复制对象时勿忘其每一个成分

    记住: ★copying函数应确保复制“对象内的所有成员变量”及“所有base class成分” ★不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两 ...

  2. EC读书笔记系列之16:条款35、36、37、38、39、40

    条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...

  3. EC读书笔记系列之1:条款1、条款2、条款3

    条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...

  4. EC读书笔记系列之20:条款53、54、55

    条款53 不要轻忽编译器的警告 记住: ★严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉 ★不要过度依赖编译器的报警能力,∵不同的编译器对待事情的态度 ...

  5. EC读书笔记系列之19:条款49、50、51、52

    条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...

  6. EC读书笔记系列之18:条款47、48

    条款47 请使用traits classes表现类型信息 记住: ★Traits classes使得“类型相关信息”在编译期可用.它们以templates和“templates特化”完成实现 ★整合重 ...

  7. EC读书笔记系列之17:条款41、42、43、44、45、46

    条款41 了解隐式接口与编译器多态 记住: ★classes和templates都支持接口和多态 ★对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函 ...

  8. EC读书笔记系列之15:条款32、33、34

    条款32 确保你的public继承塑模出is-a关系 记住: ★public继承意味着is-a.适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个deriv ...

  9. EC读书笔记系列之14:条款26、27、28、29、30、31

    条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...

随机推荐

  1. google 推荐 android 像素统一使用dip,字体统一使用sp

    像素统一使用dip,字体统一使用sp

  2. .NET系统架构改造的经验和教训

    转自: http://robbinfan.com/blog/43/rid-off-dotnet-experience 在互联网行业,基于Unix/Linux的网站系统架构毫无疑问是当今主流的架构解决方 ...

  3. 解决jQuery.live在mobile safari(iphone / ipad / ipod)绑定失败的问题

    解决方案: 给要使用live绑定事件的元素,添加“cursor:pointer”样式即可! 如: a,input,td{cursor:pointer;}

  4. Jquery揭秘系列:谈谈bind,one,live,delegate,on事件及实现

    在Jquery里面,我们用的最多的就是事件绑定了,事件绑定有多个函数.例如:bind,one,live,delegate,on等等. on() jQuery事件绑定.on()简要概述及应用 看源码发现 ...

  5. Android 常用 adb 命令总结

    Android 常用 adb 命令总结 针对移动端 Android 的测试, adb 命令是很重要的一个点,必须将常用的 adb 命令熟记于心, 将会为 Android 测试带来很大的方便,其中很多命 ...

  6. 关于在R中无法引用自己的xml文件

    查看import 是否 import android.R 有的话 删掉

  7. 将项目上传到bitbucket仓库

    先将项目添加git仓库中(本地) 成功后上门会有上传和下载按钮 提交代码:

  8. Unicode解码、URL编码/解码

    + (NSString *) stringByReplaceUnicode:(NSString *)string { NSMutableString *convertedString = [strin ...

  9. zoj1136 Multiple

    记忆化搜索,因为要求最小的,肯定是从小到大,依次添加,那么通过bfs,队列貌似是最好的选择.因为很可能那个数爆long long,所以采用字符串存储,并记录余数,通过模拟除法的方式来写. 剪枝:因为后 ...

  10. 银行卡检测中心BCTC

    BCTC是Banking Card Test Center的缩写. 银行卡检测中心(下称中心)经中国人民银行总行批准成立于1998年4月,作为一个独立的第三方专业技术检测机构,其主要职责是按照国际.国 ...