effective c++ 笔记 (23-25)
//---------------------------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)的更多相关文章
- [Effective JavaScript 笔记]第25条:使用bind方法提取具有确定接收者的方法
js里方法和属性值为函数,就像一个东西两种称呼一个样,比如土豆,也叫马铃薯,一个样.既然一样,那就可以对对象的方法提取出来为函数,然后把提取出来的函数作为回调函数直接传递给高阶函数. 高阶函数是什么 ...
- [Effective JavaScript 笔记]第3章:使用函数--个人总结
前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...
- Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记
Item 5: Know what functions C++ silently writes and calls 在C++中,编译器会自己主动生成一些你没有显式定义的函数,它们包含:构造函数.析构函 ...
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- java effective 读书笔记
java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...
- Ext.Net学习笔记23:Ext.Net TabPanel用法详解
Ext.Net学习笔记23:Ext.Net TabPanel用法详解 上面的图片中给出了TabPanel的一个效果图,我们来看一下代码: <ext:TabPanel runat="se ...
随机推荐
- HDFS Lease Recovey 和 Block Recovery
这篇分析一下Lease Recovery 和 Block Recovery hdfs支持hflush后,需要保证hflush的数据被读到,datanode重启不能简单的丢弃文件的最后一个block,而 ...
- .NET实现自动编译
前言 因每次发布版本的时候,都需要打开vs项目,然后进行编译.如果刚好手里有文件在修改,就需要先签入之类的.所以想找个可以实现自动编译的工具. 在网上查询了不少资料,终于基本上实现了自动编译的功能.因 ...
- Linux之添加交换分区
Linux下的交换分区我们可以随意改变大小,如果说日常生活中分区不够用,今天我们来举个例子如何添加. 1.首先是使用dd命令创建一个空文件,这个空文件的大小就是你要继续添加的swap的大小,比如我这里 ...
- KMP、扩展KMP、Manacher习题
照着这篇博客刷一下. 自己也做一下笔记 对于KMP算法,可以看我之前总结的这篇博客 hdu 3613 Best Reward 给一个字符串,字符由a~z构成,每个字符有一个权值.在某一点将字符串切成2 ...
- 三、git管理修改
一.修改提交 如下图,Git分工作区和版本库(.git隐藏目录中). 在每次修改后 git add "file name" 其实是把修改内容提交到本地版本库的 暂存区(stage) ...
- tcp付金卡黛珊李方军拉萨
进口量点卷啊首付款拉德斯基疯狂拉萨的
- python string.md
string 包含用于处理文本的常量和类.string模块始于Python的最早版本. 2.0版本中, 许多之前只在模块中实现的函数被转移为string对象的方法. 之后的版本中, 虽然这些函数仍然可 ...
- Failed to abandon session scope: Connection timed out
系统log 出现 Failed to abandon session scope: Connection timed out 错误, reboot无法重启 解决办法就是让postfix只用IPv4 ...
- HTTPS_SSL apache认证、配置的、步骤以及原理说明
一 .1.单向认证,就是传输的数据加密过了,但是不会校验客户端的来源 2.双向认证,如果客户端浏览器没有导入客户端证书,是访问不了web系统的,找不到地址,想要用系统的人没有证书就访问不了系统HTTP ...
- shiro实战系列(四)之配置
Shiro之配置 Shiro 被设计成能够在任何环境下工作,从最简单的命令行应用程序到最大的的企业群集应用.由于环境的多样性,使得许多配置机制适用于它的配置. 一. 许多配置选项 Shiro的Secu ...