effective c++ 笔记 (18-22)
//---------------------------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)的更多相关文章
- [Effective JavaScript 笔记]第22条:使用arguments创建可变参数的函数
第21条讲述使用可变参数的函数average.该函数可处理任意数量的参数并返回这些参数的平均值. 如何创建可变参数的函数 1.实现固定元数的函数 书上的版本 function averageOfArr ...
- [Effective JavaScript 笔记]第3章:使用函数--个人总结
前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...
- java effective 读书笔记
java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...
- SQL反模式学习笔记18 减少SQL查询数据,避免使用一条SQL语句解决复杂问题
目标:减少SQL查询数据,避免使用一条SQL语句解决复杂问题 反模式:视图使用一步操作,单个SQL语句解决复杂问题 使用一个查询来获得所有结果的最常见后果就是产生了一个笛卡尔积.导致查询性能降低. 如 ...
- JAVA自学笔记18
JAVA自学笔记18 1.Map接口: 1)功能: 2) Map<String,String>m=new HashMap<String,String>(); //添加元素,元素 ...
- 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+ ...
随机推荐
- scott/tiger is locked 解决办法
在plsql developer中要是以scott/tiger登录时提示ora-28000 the account is locked. 解决办法: 新装完Oracle10g后,用scott/tige ...
- Azure 虚拟机诊断设置问题排查
Azure 为用户提供了可以自己配置的性能监控功能:Azure 诊断扩展.但是在具体配置中,经常会遇到各种各样的问题.不了解监控的工作机制常常给排查带来一定难度.这里我们整理了关于 Azure 虚拟机 ...
- 虚拟机压力测试延迟高的可能原因及 ILPIP 配置 / 查询脚本
测试初期 Client VM 的延迟结果正常: 测试后期 Client VM 的延迟偶尔突增/连接失败,越后期超高延迟(比如 30 秒)出现越多: 问题分析 造成这一现象的根本原因很可能是 SNAT( ...
- SQL Server全文搜索(转载)
看这篇文章之前请先看一下下面我摘抄的全文搜索的MSDN资料,基本上MSDN上关于全文搜索的资料的我都copy下来了并且非常认真地阅读和试验了一次,并且补充了一些SQL语句,这篇文章本人抽取了一些本人自 ...
- Log4Net记录到文件
将这篇文章的配置文件中的log4net节点下的内容替换成下面的 https://www.cnblogs.com/RambleLife/p/9165248.html <log4net debug= ...
- linux通配符含义
linux通配符含义: . 当前目录**** .. 当前目录的上一级目录**** * 通配符,代表任意0个或多个字符***** ? 通配符,代表重复0个或一个0前面的字符 : ...
- Go语言学习笔记(六)net & net/http
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 net import "net" net包提供了可移植的网络I/O接口,包括TCP/IP.UD ...
- Hive 整合Hbase
摘要 Hive提供了与HBase的集成,使得能够在HBase表上使用HQL语句进行查询 插入操作以及进行Join和Union等复杂查询.同时也可以将hive表中的数据映射到Hbase中. 应用 ...
- 小程序push数组,渲染不出来解决办法
1.在data中,定义一个空数组: zhou_time:[] 2.声明: var zhou_time = this.data.zhou_time; 3.PUSH赋值: zhou_time.push({ ...
- RxJS--Subject
Subject是Observable(可观察对象)的子类,subject是多播的,允许将值多播给多个observer(观察者),普通observable是单播. 每一个Subject都是一个Obser ...