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 = ,
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)
最新文章
- 错误修改/etc/fstab,导致系统无法开机
- android之消息机制(二)
- 【整理贴】DBA-常用到的动态视图分析语句
- ecshop订单打印页显示商品缩略图和序号
- Codeforces 602B Approximating a Constant Range(想法题)
- bzoj 1500: [NOI2005]维修数列 splay
- php下载文件的一种方式
- 深入理解ajax系列第四篇——请求实例
- java生成首字母拼音简码的总结
- JavaScript基础:DOM操作详解
- 可前端解密的加密方法探讨和str_replace和preg_replace分析
- 解决pathForResource返回nil, 无法读取plist文件问题
- CUBA 7 新特性 (下篇)
- 软工网络15团队作业4——Alpha阶段敏捷冲刺-6
- win7下pyhton3.6创建django2的pycharm项目
- jsp table td自动换行
- 【转】org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be res
- Linux下安装Eclipse的PHP插件(PHPEclipse)
- ABC118D(DP,完全背包,贪心)
- Python基础(三)—— print()格式化输出变量
热门文章
- js仿百度文库文档上传页面的分类选择器_第二版
- Java File类读取文件属性
- UVA 1374 Power Calculus
- asp.net几种<;% %>;用法
- win10系统安装 VS 2015 安装包下载
- Oracle中字段的修改操作语法
- C++ Primer第18章Vector的再实现及bug修正
- 学习笔记-menusript控件中条目权限设置使用
- Oracle EBS-SQL (PO-5):采购订单控制信息查询.sql
- VBS解析时候遇到时间