//---------------------------15/04/06----------------------------

//#18 让接口容易被正确使用,不易被误用

{

//  1:为了防止客户输入错误的参数,可以使用外覆类型来区别:

struct Day

{

explicit Day(int d): val(d) {}

int val;

};

struct Month

{

explicit Month(int m): val(m) {}

int val;

};

struct Year

{

explicit Year(int y): val(y) {}

int val;

};

class Date

{

public:

Date(const Month& m,const Day& d,
const Year& y);

...

};

//  这时,客户职能这么使用Date class:

Date d(Month(), Day(), Year());

//  为了限制类型的值,比如一年只有12个月,Month应该反映这样的事实。

//  为了安全不直接使用enum,而是预先定义所有有效的Months:

class Month

{

public:

);}

);}

...

);}

private:

explicit Month(int m);

};

Date d(Month::Mar(), Day(), Year());

/*  2:预防客户错误的另一个办法是:限制类型内什么事可做,什么事不能做。也就是加上const。

3:除非有好理由,否则应该尽量令你的types的行为与内置types一致

4:任何接口如果要求客户必须记得做某些事情,就是有着“不正确使用”的倾向。

较佳接口的设计原则是先发制人,比如条款13中,

令factory函数返回一个智能指针,可以避免客户忘记使用智能指针:                     */

std::tr1::shared_ptr<Investment> createInvestment();

//  5:tr1::shared_ptr支持定制型删除器,可以防范DLL问题:

std::tr1::shared_ptr<Investment> createInvestment()

{

std::tr1::shared_ptr<Investment> retval(),

getRidOfInvestment);

retval = ...;

return retval;

}

}

//#19   设计class犹如设计type

{

/*  1:新type的对象应该如何被创建和销毁?

这会影响到你的class的构造函数和析构函数,以及内存分配函数和释放函数。

当然前提是如果你打算撰写他们。

2:对象初始化和对象的赋值该有什么样的差别

这个答案决定了构造函数和赋值操作符的行为,以及差异。

3:新type的对象如果被passed by value,意味着什么?

copy构造函数用来定义一个type的pass by value该如何实现。

4:什么是新type的“合法值”

你的class必须维护自己的约束条件,也就决定了你的成员函数

(特别是构造函数、赋值操作符、和所谓的setter函数)必须进行错误检查工作。

5:你的新type需要配合某个继承图系吗?

继承既有的class会受到哪些class的设计的束缚,特别是他们的函数是virtual或non_virtual的影响

如果允许别人继承自己的类,就会影响你所声明的函数是否为virtual

6:你的新type需要什么样的转换

是否需要隐式转换、显式转换。

7:什么样的操作符和函数对此新type而言是合理的?

这个答案决定你为你的class声明哪些函数,其中某些该是member函数。

8:什么样的标准函数应该驳回

你不想要系统为你声明的函数要声明为private。

9:谁该取用新type的成员

这个答案决定了哪个成员为public,protected,private。以及哪个class或function应该是friend

10:什么是新type的“为声明接口”

它对效率、异常安全性以及资源运用提供何种保证

11:你的新type有多么一般化

看看自己是否应该定义一个新的class template

12:你真的需要一个新type吗

如果只是为既有的class添加机能,那么可能单纯定义一个或多个non member函数或templates

更能达到目标。

*/

}

//#20   宁以pass by reference to const替换pass by value

{

/*  1:pass by value 需要调用copy构造函数产出一个副本,这可能使得pass by value

成为昂贵的操作。如果传递的是一个自定义class,通常需要调用一次copy构造函数加
一次析构函数

如果这个class继承自别的类,又需要多调用好几次这两个函数。

2:by reference方式传递参数可以避免slicing(对象切割)问题:

一个derived class
对象以by value方式传递并被视为一个base class对象时,base class

的copy构造函数被调用,而“造成此对象的行为属于derived class对象”的部分被切掉了,只留

下了一个base class对象。这绝不是你想要的。

3:reference通常以指针来实现出来,所以pass by reference就相当于传递指针。因此如果是一些

内置类型对象(比如int) pass by value往往比 pass by reference的效率高些。

4:除了内置类型
和 stl的迭代器和函数对象,其他的对象都以pass by reference to const

替换 pass by value。

*/

}

//#21   必须返回对象时,别妄想返回其reference

{

//  1:一些值必须返回pass by value:

//      1>通过在stack上创建对象并返回这个对象的引用:

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

{

Rantional result(lhs.n * rhs.n, lhs.d * rhs.d);

return result;

}

/*      这里有两个点:

1)这样也调用构造了,效率并没提高。

2)返回了一个已经被销毁的对象。严重的错误!

2>通过在堆上创建对象并返回这个对象的引用:

*/

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

{

Rantional result =new Rantional(lhs.n * rhs.n, lhs.d * rhs.d);

return result;

}

//      这样的话,谁负责delete?而且还是需要一次构造函数。

//      3>使用static对象:

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

{

static Rantional result;

result = ...;

return result;

}

//      这样首先线程不安全,其次使用if((a * b) == (c * d))总是返回true;

//  2:当一个函数必须返回新对象时,就让那个函数返回一个新对象呗!

inline
const Rantionaloperator* (const Rantional& lhs,const Rantional& rhs)

{

return Rantional(lhs.n * rhs.n, lhs.d * rhs.d);

}

}

//#22   将成员变量声明为private

{

/*  1:首先看看成员变量不该是public:

1>一致性:如果没有public成员变量,客户唯一能访问对象的办法就是使用成员函数

客户就不需要在访问成员时疑惑地试着记住是否使用小括号。

2>可以更加精准地控制成员变量:你可以通过函数控制成员变量的读写。

3>封装性:如果通过函数访问成员变量,日后就算更改了这个变量的计算方法,或者直接更改了变量,

客户也不知道,也不必知道。

不封装就意味着不改变。

2:成员变量不该是protected:

道理和public第三点一样,这样对derived class并没有封装性可言

}

effective c++ 笔记 (18-22)的更多相关文章

  1. [Effective JavaScript 笔记]第22条:使用arguments创建可变参数的函数

    第21条讲述使用可变参数的函数average.该函数可处理任意数量的参数并返回这些参数的平均值. 如何创建可变参数的函数 1.实现固定元数的函数 书上的版本 function averageOfArr ...

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

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

  3. java effective 读书笔记

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

  4. SQL反模式学习笔记18 减少SQL查询数据,避免使用一条SQL语句解决复杂问题

    目标:减少SQL查询数据,避免使用一条SQL语句解决复杂问题 反模式:视图使用一步操作,单个SQL语句解决复杂问题 使用一个查询来获得所有结果的最常见后果就是产生了一个笛卡尔积.导致查询性能降低. 如 ...

  5. JAVA自学笔记18

    JAVA自学笔记18 1.Map接口: 1)功能: 2) Map<String,String>m=new HashMap<String,String>(); //添加元素,元素 ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Oracle EBS 新增 OAFM 个数

    在 $INST_TOP/ora/10.1.3/opmn/conf/opmn.xml中 找到 <process-type id="oafm" module-id="O ...

  2. Visual Studio 2010详细安装过程

    Visual Studio 2010在目前看来,应该是使用得比较多的一款微软的软件开发工具集合了,因为它具有以下优点:(1)启动速度快:在相同环境下,相比于Visual Studio 2015来说,2 ...

  3. 如何让VB6代码编辑器垂直滚动条随鼠标滚轮滚动

    VB6毕竟是很老的产品了,它的代码编辑器垂直滚动条并不能随鼠标的滚轮而滚动,这个问题会让我们在编写代码的时候觉得很不方便,不过还是有一种方法可以解决这个问题的.    先下载一个微软发布的“VB6ID ...

  4. CentOS配置rsyslog Serve

    CentOS6配置rsyslog Server: vi /etc/rsyslog.conf: #启用如下tcp支持: $ModLoad imtcp $InputTCPServerRun 514 #添加 ...

  5. cron定时任务介绍

    什么是cron? Cron是linux系统中用来定期执行或指定程序任务的一种服务或软件.与它相关的有两个工具:crond 和 crontab.crond 就是 cron 在系统内的宿主程序,cront ...

  6. Nginx 配置支持 WebSocket

    找到nginx的配置文件:nginx.conf,增加以下三行配置. 示例: server { listen 80; server_name www.test.com; location / { pro ...

  7. Windows 下的文件被占用问题解决

    windows下,经常容易出现文件被其他程序占用的现象,令人十分头疼.更头疼的是,还看不到被谁占用. 实际上是有办法看到占用的进程的. 话不多说,以Win10为例: 1.打开资源监视器 a.直接程序栏 ...

  8. 使用let声明变量的理解

    先看阮大神的[ECMAScript 6 入门]中关于这一部分的描述 var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { ...

  9. BZOJ3155:Preprefix sum(线段树)

    Description Input 第一行给出两个整数N,M.分别表示序列长度和操作个数 接下来一行有N个数,即给定的序列a1,a2,....an 接下来M行,每行对应一个操作,格式见题目描述 Out ...

  10. 【洛谷】【动态规划+单调队列】P1714 切蛋糕

    [题目描述:] 今天是小Z的生日,同学们为他带来了一块蛋糕.这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值. 小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但 ...