//---------------------------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. Go 在 TiDB 的实践

    https://blog.csdn.net/RA681t58CJxsgCkJ31/article/details/79215751 更多TiDB链接: https://my.oschina.net/z ...

  2. C#程序如何捕捉未try/catch的异常——不弹“XXX已停止工作”报错框

    诚意满满直接上代码: static void Main(string[] args) { //Main函数中增加此句 AppDomain.CurrentDomain.UnhandledExceptio ...

  3. win7 win10双系统开机系统引导

    以win7启动管理器引导作为启动引导 安装一个easybcd 然后里面添加引导选项(添加新条目---->编辑引导菜单(选择倒计时30秒)把use metro bootloader勾去掉就是默认的 ...

  4. 基于Java反射的map自动装配JavaBean工具类设计

    我们平时在用Myabtis时不是常常需要用map来传递参数,大体是如下的步骤: public List<Role> findRoles(Map<String,Object> p ...

  5. objc.io 待看文章

    https://objccn.io/issues/ https://objccn.io/issues/ 使用 VIPER 构建 iOS 应用 并发编程

  6. 可以获取JVM信息的一些管理工具类

    一些可以获取JVM信息的java工具类 BufferPoolMXBean.class ClassLoadingMXBean.class CompilationMXBean.class GarbageC ...

  7. Linux之Vim学习

    Linux之Vim学习 一般模式 光标移动 按键 作用 j或down方向键 向下移动一个字符 k或up方向键 向上移动一个字符 h或left方向键 向左移动一个字符 l或right方向键 向右移动一个 ...

  8. vagrant特性——基于docker开发环境(docker和vagrant的结合)-4-简单例子-有问题

    运行一个十分简单的例子: Vagrant.configure() do |config| config.vm.provider "docker" do |d| d.image = ...

  9. 11.C++和C的区别,什么是面向对象

    c++封装更好,调用接口,c调用子函数 1.首先C和C++在基础语句上没有太大区别,c++在c基础上改进,兼容大部分c的语法结构.c++面向对象,c面向过程. 2.新增new和delete的语法,引用 ...

  10. jenkins自动部署到tomcat报错:ERROR: Publisher hudson.plugins.deploy.DeployPublisher aborted due to exception

    参考地址: http://blog.csdn.net/weiguang1017/article/details/9011353 manager-script — Access to the tools ...