条款23和条款24

简介: 条款23和条款24

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

为什么要用非成员函数、非友元函数替换成员函数呢?其实这是为了保证数据的封装性。而数据的封装性强弱是怎么体现的呢?一种粗糙的量测,我们认为越多的函数能访问它,数据的封装性就越低,因为如果数据发生改变,因它的改变牵扯到需要改变的太多,所以它的封装性较差。

而非成员函数、非友元函数较成员函数而言,访问不到private中的数据,数据的封装性自然就更好一些。也就是说,越多的函数可以访问,数据的封装性就越低。

需要注意的是,只因在意封装性而让函数“成为class的non-member”,并不意味它“不可以是另一个class的member”。该函数可以成为另一个类的static member函数,只要不影响原类中private成员的封装性。

看一下书中的例子:

class WebBrowser {
public:
  void clearCache();
  void clearHistory();
  void removeCookies();
}

现在有这样一个类,类中提供三种方法用来清除web浏览器的一些缓存。如果我们想一起清除Cache、History、Cookies,我们可以将这三个函数放在一个成员函数中去做,这样每次只需调用一个函数就行。

class WebBrowser{
public:
  void clearEverything(); //调用clearCache(),clearHistory(),removeCookies()
}

clearEverything()是一个成员函数,条款中不是说宁以non-member、non-friend替换member吗?因此,可以这样做:

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

让它成为一个非成员函数。

而在c++中我们通常可以将类和有关该类的非成员函数放在同一命名空间中,就像这样:

namespace WebBrowserStuff {
  class WebBrowser {...};
  void clearBrowser(WebBrowser& wb);
  ...
}

同时,与WebBrowser类有关的便利函数,可能有多个,以及多个种类,比如,与cookie相关的,还有与书签相关的等等。为了减少没必要的依赖(比如,我现在只想用与cookie相关的函数,也就没必要引入与书签相关的函数),我们可以将他们分别声明在不同的头文件中,但都属于WebBrowserStuff这一命名空间,因为,他们都是与WebBrowser有关的。

//头文件“webbrowser.h”这个头文件针对class WebBrowser自身及WebBrowser核心机能。
namespace WebBrowserStuff {
  class WebBrowser {...};
  ...   //核心机能,例如几乎所有客户都需要的non-member函数
}
//头文件“webbrowserbookmarks.h”
namespace WebBrowserStuff {
  ...   //与书签相关的便利函数
}
//头文件“webbrowsercookies.h”
namespace WebBrowserStuff {
  ...   //与cookie相关的便利函数
}

将便利函数放在多个头文件中但都属于同一命名空间,意味着我们可以轻松的在此基础上增加其他的便利函数,这也是命名空间较class好的一点,class是一个整体,对于用户来说不能扩展,而命名空间可以。

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

现在我们定义一个有理数的类:

class Rational {
public:
  Rational(int numerator = 0, int denominator = 1);
  int numerator() const;
  int denominator() const;
private:
  ...
}

有理数相乘似乎是很正常的事,为此,在类中重载一下乘法运算:

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

这样便可支持两个有理数相乘:

Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEighth;
result = result * oneEighth;

让有理数和整数相乘似乎也是很正常的事,当我们执行:

result = oneHalf * 2;//正确
result = 2 * oneHalf;//错误

可以发现,其中一个报错,这是因为,oneHalf是一个内含operator*函数的class的对象,所以编译器调用该函数。而整数2没有相应的class,也就没有operator*成员函数。编译器尝试非成员函数operator*(也就是在命名空间内或在global作用域内),然而其他地方也没有相关定义,因此报错。再来看result = oneHalf * 2,这个为什么正确呢?其实这里涉及到一个隐式的类型转换,即2通过构造函数转换为一个Rational类型,两个Rational类型相乘,自然没有报错。

只有当参数被列于参数列内,这个参数才是隐式类型转换的合格参与者,正如result = oneHalf * 2一样。对于出错的情况,我们可以重载一个非成员函数的乘法运算:

class Rational {
  ...
};
const Rational operator*(const Rational& lhs, const Rational& rhs) {
  return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}

其实上述两种重载方式称为类内重载和类外重载,当两种重载方式同时存在时,编译器会优先使用类内重载,因为类内重载对于类的使用者来说是优先可见的,因此它的优先级更高(对于类的使用者而言,优先看到的肯定是意图中想用的)。

相关文章
|
供应链 前端开发
阿里成立数据智能新公司,瓴羊的独立始末
(转载报道媒体:晚点LatePost)推动瓴羊形成的过程中,阿里管理层选择了更激进、整合度更高的方案,选择了多平台、多云的定位。中国互联网发展二十多年,从开放走向封闭,或主动或被动,现在它正重新走向开放,这是大势所趋。
阿里成立数据智能新公司,瓴羊的独立始末
|
监控 Devops 中间件
阿里巴巴DevOps实践指南(十四)| 测试环境与路由
在阿里巴巴内部,随着业务规模和技术栈的拓展和更新,业务侧对测试环境的使用也逐步打破原固有模式,快速向多场景、多样化、多职能方向发展,如何能够跟上业务发展速度,及时满足业务侧对测试环境新场景的诉求,基于环境和路由模型的测试环境解决方案是解决问题的关键。
阿里巴巴DevOps实践指南(十四)| 测试环境与路由
|
存储 对象存储 UED
CDN适用哪些场景?
CDN是将源站内容分发至最接近用户的节点,使用户可就近取得所需内容,提高用户访问的响应速度和成功率。今天为大家分享几个CDN的典型适用场景。
16622 0
|
10月前
|
人工智能 安全 搜索推荐
AI 驱动研发模式升级,蓝凌软件探索效率提升之道
蓝凌软件在引入通义灵码后取得了较明显的效果。目前,蓝凌软件已使用灵码的开发人员中,周活跃用户占比超过90%、根据代码库自动生成的代码占比超33%、代码智能补全占比29%,代码注释率提升了15%,有效提升了产品代码工程化的效能。
|
机器学习/深度学习 人工智能 运维
预约直播 | 流批一体机器学习算法平台Alink介绍及应用
阿里云AI技术分享会第五期《流批一体机器学习算法平台Alink介绍及应用》将在2022年10月12日晚18:00开启直播,精彩不容错过!
预约直播 | 流批一体机器学习算法平台Alink介绍及应用
|
SQL 缓存 监控
MySQL高并发场景实战 ——凌洛
MySQL高并发场景实战 ——凌洛
1360 23
MySQL高并发场景实战  ——凌洛
|
运维 NoSQL 安全
图解MongoDB数据库学习路线指南
文章目录 1、MongoDB数据库学习大纲 2、MongoDB数据格式 3、MongoDB数据库特点 4、MongoDB数据库应用场景 5、MongoDB数据库单节点部署 5、MongoDB数据库常用操作指令 6、MongoDB数据库增删改查数据查询 7、MongoDB数据库运维工具 8、MongoDB授权登陆安全模式 9、MongoDB副本集集群 10、MongoDB数据备份恢复机制 11.MongoDB数据误删除恢复流程
721 0
图解MongoDB数据库学习路线指南
|
缓存 运维 Kubernetes
微服务应用实现无损上下线最佳实践
本文是阿里云微服务引擎MSE在应用发布时提供的无损上下线和服务预热能力最佳实践介绍。
3825 1
|
存储 弹性计算 编解码
租用阿里云服务器8核16G配置一年多少钱?公网带宽和系统盘是如何收费的?
本文介绍了阿里云服务器8核16G配置最新的租用费用,包含收费标准及最新活动价格和公网带宽和系统盘收费情况以及后续升级续费最新优惠政策等。
1185 0
租用阿里云服务器8核16G配置一年多少钱?公网带宽和系统盘是如何收费的?

热门文章

最新文章