//---------------------------15/04/08----------------------------

//#23   宁以non_member、non_friend替换member函数

{

class WebBrowser

{

public:

...

void clearCache();

void clearHistory();

void removeCookies();

...

};

/*  对于上面这个函数,有的客户会想一次调用这三个函数,那么时使用member函数好呢,

还是non_menber non_friend函数好呢

1:对于封装性来说,是non_member版本比较好。

1>从封装开始讨论:如果某东西被封装,它就不再可见。愈多东西被封装,愈少人可以看到它。

而愈少人看到它,就有愈大的弹性去变化它,因为我们的改变仅仅直接影响看到改变的那些人事物。

就这一点来说,能够访问private成员变量的就是成员函数和friend函数。如果non_member和

member函数提供的功能是相同的,那么,封装性较大的是non_member函数,因为它不增加”能访问

class内private成分“的数量。

2>member函数说的只是针对能访问到private成员的类,并不是说这个函数不能是别的类的member函数。

2:把这些non_member函数放入namespace并分类到不同的头文件中。这么做的原因是,客户可以针对不同的

功能,包含不同的头文件。

*/

}

//#24   若所有参数皆需类型转换,请为此采用non_member函数

{

//  令class支持隐式类型转换通常是个糟糕的主意。然而也有例外,最常见的例外是在建立数值类型时。

//  如果要设计一个有理数的类,让他支持int隐式转换到有理数还是很合理的

class Rational

{

public:

Rational(,
)//没有使用explicit,允许隐式转化

int numerator()
const;

int denominator()
const;

private:

};

//  让有理数类支持+ *等操作时,使用non_member函数实现,类内部的operatpr*()操作无法实现全部功能。

const Rational
operator*(const Rational& rhs)const;

Rational oneHalf(,),result;

;  //可以正确调用operator*()操作,2在参数列表中,可以隐式转换

result = * oneHalf;  
//错误,没有这样的操作

//  结论:只有当参数被列于参数列表内,这个参数才是隐式类型转换的合格参与者。

//  所以,只能使用non_member函数,把两个数都放入参数列表中

const Rational
operator*(const Rational& lhs,const Rational& rhs)

{

return Rational(lhs.numerator() * rhs.numerator(),

lhs.denominator() * rhs.denominator());

}

//  是否让它成为friend的?没有必要,不是friend就能完成任务,就不必成为friend了

}

//#25   考虑写出一个不抛异常的swap函数

{

//  swap原本是stl的函数:

namespace std

{

template<typename T>

void swap(T& a, T& b)

{

T temp(a);

a = b;

b = temp;

}

}

//  这种调用方式,在某些情况,会产生不必要的消耗:

class WidgetImpl

{

public:

...

private:

int a,b,c;

stad::vector<double> v;//意味着复制需要的时间很长

};

class Widget

{

public:

Widget(const Widget& rhs);

Widget&operator=(const Widget& rhs)

{

...

*pImpl = *(rhs.pImpl); //深拷贝

...

}

private:

WidgetImpl* pImpl;

};

//  当执行swap的时候,正常情况应该直接交换两个 pImpl的指针,而stl版本的却要复制三个widgetImpl对象

//  为了特化,可以声明一个成员函数对指针调用swap函数:

class Widget

{

public:

void swap(Widget& other)

{

using std::swap;

swap(pImpl, other.pImpl);

}

...

};

namespace std

{

template<>

void swap<Widget>(Widget& a, Widget& b)

{

a.swap(b);

}

}

//  当Widget时个class template时,这么做是错的:

namespace std

{

template<typename T>

void swap< Widget<T> >(Widget<T>& a, Widget<T>& b)

{

a.swap(b);

}

}

//  这样是在偏特化 swap的函数模版参数,并不是偏特化swap函数,所以可以使用重载:

namespace std

{

template<typename T>

void swap(Widget<T>& a, Widget<T>& b)

{

a.swap(b);

}

}

//  然而我们不能往std中添加新的东西。所以我们可以把non_member函数放到Widget的namespace那儿

namespace WidgetStuff

{

template<typename T>

class Widget{...};

...

template<typename T>

void swap(Widget<T>& a, Widget<T>& b)

{

a.swap(b);

}

}

//  使用

template<typename T>

void doSomething(T& obj1, T& obj2)

{

using std::swap;       
//为了std的swap可见,至于调不调用是编译器的事

...

swap(obj1, obj2);

}

/*  swap总结:

1>提供一个public swap成员函数,让它高效地置换你的类型的两个对象值。

2>在你的class或template所在的命名空间内提供一个non_member swap,并令它调用上述swap成员函数

3>如果你编写的class不是class template。为你的class特化std::swap,并令让调用swap成员函数。

4>在使用swap时,记得使用 using std::swap,使得std::swap可见。

5>成员版swap绝对不能抛出异常。

*/

}

effective c++ 笔记 (23-25)的更多相关文章

  1. [Effective JavaScript 笔记]第25条:使用bind方法提取具有确定接收者的方法

    js里方法和属性值为函数,就像一个东西两种称呼一个样,比如土豆,也叫马铃薯,一个样.既然一样,那就可以对对象的方法提取出来为函数,然后把提取出来的函数作为回调函数直接传递给高阶函数. 高阶函数是什么 ...

  2. [Effective JavaScript 笔记]第3章:使用函数--个人总结

    前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...

  3. Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记

    Item 5: Know what functions C++ silently writes and calls 在C++中,编译器会自己主动生成一些你没有显式定义的函数,它们包含:构造函数.析构函 ...

  4. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  5. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  6. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  7. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  8. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  9. java effective 读书笔记

    java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...

  10. Ext.Net学习笔记23:Ext.Net TabPanel用法详解

    Ext.Net学习笔记23:Ext.Net TabPanel用法详解 上面的图片中给出了TabPanel的一个效果图,我们来看一下代码: <ext:TabPanel runat="se ...

随机推荐

  1. Django开发笔记(一)

    Django开发笔记(一) 标签(空格分隔): Django Python 1. 创建并运行Django项目 创建开发环境 安装Django pip install django==version 执 ...

  2. 表的垂直拆分和水平拆分-zz

    https://www.kancloud.cn/thinkphp/mysql-design-optimalize/39326 http://www.cnblogs.com/nixi8/tag/mysq ...

  3. 解决:Tomcat 局域网IP地址 访问不了

    解决:Tomcat 局域网IP地址 访问不了 2014年10月17日 ⁄ 综合 ⁄ 共 1000字 ⁄ 字号 小 中 大 ⁄ 评论关闭 如果连最基本的localhost:8080都失败的话. 原因就一 ...

  4. MFC 常用功能总结

    目录 ◆ 获取启动参数◆ 调整窗体大小◆ 关闭Dialog窗体◆ Dialog启动时指定控件为焦点◆ Dialog中禁止ESC回车关闭窗体◆ 回车后焦点自动跳到下一个控件◆ 窗体中某个控件捕获右键菜单 ...

  5. 【2017下集美大学软工1412班_助教博客】团队作业4——Alpha冲刺日志公示

    作业要求 团队作业4--第一次项目冲刺(Alpha版本) 团队评分结果和评分标准 检查项 总分 会议内容 代码签入 心得体会或其他记录 燃尽图 会议照片 评论区反馈 组别 分值 10 2 2 2 1 ...

  6. Fedora29 安装 spring tool suite 4.2

    下载安装包 下载地址:https://spring.io/tools 文件:STS-4.2.0.RELEASE.tar.gz 解压部署软件包 解压文件至 /opt/STS-4.2.0.RELEASE/ ...

  7. 用python实现MRO算法

    引子: 如图反映了python3中,几个类的继承关系和查找顺序.对于类A,其查找顺序为:A,B,E,C,F,D,G,(Object),这并不是一个简单的深度优先或广度优先的规律.那么这个顺序到底是如何 ...

  8. python批量连接mysql

    注释:脚本(gomysql.py)需要进一步优化,初学者,努力中 首先配置需要执行的dbip.ini列表,格式如下 S1  192.168.0.5   3306  dbusername dbpassw ...

  9. 乐视4.14硬件免费日de用户体验

    此贴用于记录2016年4月14日乐视硬件免费日购买X65超级电视的用户体验.后续将动态更新 我是乐视电视的第一批用户,从乐视上市第一批超级电视,我先后帮助家人.同事.朋友买了6台乐视超级电视,也算是乐 ...

  10. div宽度随屏幕大小变化

    题目: 一个页面上两个div左右铺满整个浏览器, 要保证左边的div一直为100px,右边的div跟随浏览器大小变化, 比如浏览器为500,右边div为400,浏览器为900,右边div为800. 方 ...