条款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)

最新文章

  1. 错误修改/etc/fstab,导致系统无法开机
  2. android之消息机制(二)
  3. 【整理贴】DBA-常用到的动态视图分析语句
  4. ecshop订单打印页显示商品缩略图和序号
  5. Codeforces 602B Approximating a Constant Range(想法题)
  6. bzoj 1500: [NOI2005]维修数列 splay
  7. php下载文件的一种方式
  8. 深入理解ajax系列第四篇——请求实例
  9. java生成首字母拼音简码的总结
  10. JavaScript基础:DOM操作详解
  11. 可前端解密的加密方法探讨和str_replace和preg_replace分析
  12. 解决pathForResource返回nil, 无法读取plist文件问题
  13. CUBA 7 新特性 (下篇)
  14. 软工网络15团队作业4——Alpha阶段敏捷冲刺-6
  15. win7下pyhton3.6创建django2的pycharm项目
  16. jsp table td自动换行
  17. 【转】org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be res
  18. Linux下安装Eclipse的PHP插件(PHPEclipse)
  19. ABC118D(DP,完全背包,贪心)
  20. Python基础(三)—— print()格式化输出变量

热门文章

  1. js仿百度文库文档上传页面的分类选择器_第二版
  2. Java File类读取文件属性
  3. UVA 1374 Power Calculus
  4. asp.net几种<% %>用法
  5. win10系统安装 VS 2015 安装包下载
  6. Oracle中字段的修改操作语法
  7. C++ Primer第18章Vector的再实现及bug修正
  8. 学习笔记-menusript控件中条目权限设置使用
  9. Oracle EBS-SQL (PO-5):采购订单控制信息查询.sql
  10. VBS解析时候遇到时间