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

non-member/non-friend可以给对象带来更大的封装性,从两个方面来考虑:1)考虑封装,越多东西被封装,它们就越不可见,就越少人看到它,就会越有弹性去改变它;2)考虑对象内的数据,越少代码可以看到数据,越多的数据被封装,那么我们就越能自由地改变对象数据;

在C++中,可以让所有的non-member函数放在同一个命名空间内,然后使用那个命名空间;C++标准程序库并不是单一、整体、庞大的头文件,而是很多头文件组合而成的,这就允许客户只对他们所有的那部分系统形成编译相依;

条款24:若所有参数都需类型转换,用non-member代替member函数

对于参数都允许发生隐式转换的函数,使用non-member函数可以使你的类功能更加具有一致性,而且还支持混合式算术编程;具体代码分析如下:

const rational operator*(const rational&rhs)const{

return rational(this->numerator( )*rhs.numerator( ),this->denominator( )*rhs.denominator( );

}

rational onehalf(1,2);

rational result=2*onehalf;//错误,调用实际情况是2.operator(&2,onehalf);//不能对常量取地址操作

rational result=onehalf*2;//正确

修改为non-member函数

const rational operator*(const rational& lhs ,  const rationa & rhs){

return rational(lhs.numerator( )*rhs.numerator( ),lhs.denominator( )*rhs.denominator( );

}

结论:如果你需要为某个函数的所有参数(this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member;

条款25:考虑写出一个不抛异常的swap函数

swap原本是STL中的一部分,后成为异常安全性编程的脊柱以及用来处理自我赋值可能的一种常见机制;

1.缺省情况下,std标准库的swap算法:

template<typename T>

void swap(T&a,T&b){T temp(a);a=b;b=temp;}//实现是基于T的copy构造函数和copy assignment完成

2.通常情况下,数据的表现形式都是“以指针指向一个对象,内含真正的数据”,这种设计模式通常变现为pimpl(pointer to implementation)手法,如:

class widgetimpl{                                            class widget{

private:                                                             private:

int a ,b,c;                                                           widgetimpl*pimpl;

std::vector<double>v;                              };

}

如果需要交换两个widget对象,那么我们唯一需要做的就是交换两个pimpl指针,但是普通的swap算法却是复制了三次widgetimpl;

解决上述问题的一个方法:就是将std::swap针对widget全特化(模板函数的一个实例),然后用widget的成员函数调用它(写错了)用全特化的swap函数来调用public swap成员函数,具体代码如下:

class widget{                                                       namespace std{

public:                                                                            template<>//针对widget的特化版本

void swap(widget&other){                           void swap<widget>(widget&a.widget&b){

  using std::swap;//让std内的swap可用                            a.swap(b);            //调用swap成员函数;

swap(pimpl,other.pimpl);                                  }

};                                                                       }

3.如果widget和widgetpimpl都是class templates而非class,那么我们重新定义非成员函数;

template<typename T>

void swap<widget<T>>(widget<T>&a,widget<T>&b){ a.swap(b);}       //不合法,错误

原因是我们企图对function template偏特化,但是C++只允许对class template偏特化;

引申:std是一个特殊的命名空间,其管理规则也比较特殊,客户可以全特化(实例化)std内的template,但是不可以添加新的templates(class或者templates或者其他的任何东西)到std里头,C++禁止这类行为,但是编译器却不会报错,但是软件可能会出现不可预期的行为;

解决上述问题的一个办法:添加一个重载函数来代替我们要做的偏特化一个function template行为,我们还是声明一个non-member swap函数让他调用member swap,但不再声明将那个non-member swap声明为std::swap的特化版本,具体实现代码如下:

template<typename T>                                                   template<typename T>

class widget{                                                                     void swap(T&obj1,T&obj2){

public:                                                                                         using std::swap;

void swap(widget&other){                                                   swap(obj1,obj2);//T型对象的最佳调用swap版本

  using std::swap;                                                     }   //优先调用T专属版本,即public swap成员函数

swap(pimpl,other.pimpl);                                         //并在该版本不存在的情况下调用std内一般化的版本

}

结论:1)如果swap缺省实现码可以实现你的class或者class template提供可接受的效率,你不需要做任何事情;

2)如果swap缺省码不够实现你的效率,你可以:

a)提供一个public swap成员函数,让它处理两个对象值;

b)在你所在的class或者template所在的命名空间内提供一个non-member swap,并令它调用上述swap成员函数;

c)如果你在编写一个class(而非class template),为你的class特化std::swap,并令它调用你的swap成员函数。

3)如果你调用swap,确定包含一个using声明式,以便std::swap在你的函数内曝光,然后不加namespace,单纯调用swap(使swap函数有更多的选择);

成员版的swap绝不可能抛出异常,因为swap的一个最好应用就是帮助classes提供强烈的异常安全性保障(以copy构造函数和copy assignment操作符为基础的);

引申:关于模板的全特化和偏特化描述,可以参考博文:https://www.cnblogs.com/yyehl/p/7253254.html

Effective C++学习第七天相关推荐

  1. Effective C++ 学习笔记 第七章:模板与泛型编程

    第一章见 Effective C++ 学习笔记 第一章:让自己习惯 C++ 第二章见 Effective C++ 学习笔记 第二章:构造.析构.赋值运算 第三章见 Effective C++ 学习笔记 ...

  2. python字典、列表、元祖使用场景_python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍...

    python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍 一丶元祖 1.元祖简介 元祖跟列表类似.只不过是有区别的. 如下: tuple(元祖英文) 跟列表类似, 元素不能 ...

  3. Maven学习总结(七)——eclipse中使用Maven创建Web项目

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(七)--eclipse中使用Maven创建Web项目 一.创建Web项目 1.1 选择建立Maven Pr ...

  4. 学习Kotlin(七)反射和注解

    推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...

  5. 从零开始学习jQuery (七) jQuery动画-让页面动起来!

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  6. Typescript 学习笔记七:泛型

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  7. Java IO流学习总结七:Commons IO 2.5-FileUtils

    Java IO流学习总结七:Commons IO 2.5-FileUtils 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/5497 ...

  8. (转)Maven学习总结(七)——eclipse中使用Maven创建Web项目

    孤傲苍狼 只为成功找方法,不为失败找借口! Maven学习总结(七)--eclipse中使用Maven创建Web项目 一.创建Web项目 1.1 选择建立Maven Project 选择File -& ...

  9. php函数知识点,php入门学习知识点七 PHP函数的基本应用_php基础

    /* * 简单的函数 */ function fontBold($con){ return "$con"; } $str="简单的函数测试!"; echo &q ...

最新文章

  1. Java Web中的Filter和Interceptor的区别
  2. DeepStream开发日志
  3. 【Python基础】使用Matplotlib可视化数据的5个强大技巧
  4. P2575 高手过招
  5. java c语言 for_Java能写C语言编译器吗
  6. 2018年《大数据》杂志调查问卷
  7. 服务器温度检测软件_科技产品—整机柜服务器—产品简介
  8. Uploadify—借助Uploadify插件实现图片预览时如何解决Chrome浏览器报“喔唷,崩溃啦”
  9. 【毕业设计】 python小游戏设计 - 走迷宫游戏设计与实现
  10. python怎么重复程序,如何重复运行python程序
  11. 25款实用的桌面版博客编辑器
  12. STM32+IR2104S的H桥电机驱动电路详解
  13. Android锁屏勒索病毒分析(4)秒抢红包
  14. 如何通过知识付费盈利,实现内容变现?
  15. golang下文件锁的使用
  16. how to define the RASIC in a team
  17. 【盲解调】基于频率和滤波器参数估计的FH-GFSK调制信号盲解调算法matlab仿真
  18. css+全屏视频背景+响应式布局
  19. 空间光调制器(SLM)属于反射型模拟调制矩阵液晶模块
  20. thinkjs查询mysql_Mysql · ThinkJs2.0开发手册 · 看云

热门文章

  1. 创建vue项目(一)搭建vue-cli、项目文件介绍、简单配置
  2. Unity3D入门其实很简单
  3. 给div命名,使逻辑更加清晰
  4. ubuntu下如何查找某个文件的路径
  5. !+\v1 用来“判断浏览器类型”还是用来“IE判断版本”的问题!
  6. STL中的lower_bound和upper_bound的理解
  7. 谈谈Hybird3D中的光栅化优化
  8. Oracle数据库的备份
  9. extjs中xtype类型
  10. 广元南山隧道南河互通立交图_广元城区一隧道工程竣工时间已定,今后出行更加方便了!...