//---------------------------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. HDFS Lease Recovey 和 Block Recovery

    这篇分析一下Lease Recovery 和 Block Recovery hdfs支持hflush后,需要保证hflush的数据被读到,datanode重启不能简单的丢弃文件的最后一个block,而 ...

  2. .NET实现自动编译

    前言 因每次发布版本的时候,都需要打开vs项目,然后进行编译.如果刚好手里有文件在修改,就需要先签入之类的.所以想找个可以实现自动编译的工具. 在网上查询了不少资料,终于基本上实现了自动编译的功能.因 ...

  3. Linux之添加交换分区

    Linux下的交换分区我们可以随意改变大小,如果说日常生活中分区不够用,今天我们来举个例子如何添加. 1.首先是使用dd命令创建一个空文件,这个空文件的大小就是你要继续添加的swap的大小,比如我这里 ...

  4. KMP、扩展KMP、Manacher习题

    照着这篇博客刷一下. 自己也做一下笔记 对于KMP算法,可以看我之前总结的这篇博客 hdu 3613 Best Reward 给一个字符串,字符由a~z构成,每个字符有一个权值.在某一点将字符串切成2 ...

  5. 三、git管理修改

    一.修改提交 如下图,Git分工作区和版本库(.git隐藏目录中). 在每次修改后 git add "file name" 其实是把修改内容提交到本地版本库的 暂存区(stage) ...

  6. tcp付金卡黛珊李方军拉萨

    进口量点卷啊首付款拉德斯基疯狂拉萨的

  7. python string.md

    string 包含用于处理文本的常量和类.string模块始于Python的最早版本. 2.0版本中, 许多之前只在模块中实现的函数被转移为string对象的方法. 之后的版本中, 虽然这些函数仍然可 ...

  8. Failed to abandon session scope: Connection timed out

    系统log 出现  Failed to abandon session scope: Connection timed out  错误, reboot无法重启 解决办法就是让postfix只用IPv4 ...

  9. HTTPS_SSL apache认证、配置的、步骤以及原理说明

    一 .1.单向认证,就是传输的数据加密过了,但是不会校验客户端的来源 2.双向认证,如果客户端浏览器没有导入客户端证书,是访问不了web系统的,找不到地址,想要用系统的人没有证书就访问不了系统HTTP ...

  10. shiro实战系列(四)之配置

    Shiro之配置 Shiro 被设计成能够在任何环境下工作,从最简单的命令行应用程序到最大的的企业群集应用.由于环境的多样性,使得许多配置机制适用于它的配置. 一. 许多配置选项 Shiro的Secu ...