effective c++ 笔记 (35-40)
//---------------------------15/04/24----------------------------
//#35 考虑virtual函数以外的其他选择
{
/*
1:通常情况下对于有变动的东西,我们都会设计成virtual函数,然后由子类来继承,并重新实现,
但是,由于这个惯性思维,成了弱点。因为我们这样就没有想过别的实现方法。
2:用Non-Virtual Interface来代替virtual函数。
1>把virtual函数设计成private,并使用别的public函数调用。这里有一个很关键的一点:
private virtual函数能实现多态么?答案是肯定的。尽情地重定义吧。
2>在调用virtual函数的前后可以加上一些自己的控制,比如上锁,记录等等一切你想做的。
3>其实也不一定必须是private的,自己看情况定义吧。
3:使用Strategy模式:
1>当你需要virtual函数时,可以考虑存储一个仿函数对象,然后在一个public函数中调用这个
仿函数。
2>这个仿函数内部的操作不应该依赖于类的内部细节,不然还是乖乖用virtual函数来的好。
3>这时你会发现,可以动态地改变要调用的函数,比如一个计算血量值的函数,可以一开始调用
正常版本的,当角色中毒什么的,就换一个计算血量的函数。哇!cool。
*/
}
//#36 绝不重新定义继承而来的non-virtual函数
{
/*
前提:D public继承自 B
先看两个准则(前面的条款已经将过的):
1>适用于B对象的每一件事,也使用于D对象,因为每个D对象 is-a
B对象。
2>D一定会继承B的non-virtual函数的接口和实现。
所以,如果我们重新定义了一个non-virtual函数:
1>D以public方式继承B,那么当D有一个函数需要重新定义(不变性凌驾特异性),这个函数
应该为virtual的而不是non-virtual的。
2>如果这个函数不需要被重定义(特异性凌驾不变性),那么D久不需要重定义mf,而且它也
不应该尝试这么做。
所以结论是:不要重定义继承而来的non-virtual函数。
*/
}
//#37 绝不重定义继承而来的缺省参数值
{
// 1:看下这两个函数:
class Shape
{
public:
enum ShapeColor{Red, Green, Blue};
virtual void draw(ShapeColor color = Red)
;
};
class Rectangle :
public Shape
{
public:
virtual void draw(ShapeColor color = Green)
const;
};
/*
这么做的结果就是:当客户使用基类指针,子类对象时,调用的内容是子类的,默认参数确实基类的。
这样子做没有意义,所以问题朝着两个方向发展:
1>你想切换默认参数。
2>你想保留默认参数,但是切换调用的内容。如果子类也要使用相同的参数,那么如果默认参数一改变
基类和子类的都必须改变,所以这很糟糕。
实现起来很简单嘛:
1>想切换参数?定义一个non-virtual函数,然后用virtual的函数调用之,
调用时传入不同的参数就ok了。
2>想切换调用内容?定义一个private virtual函数,然后用带着默认参数的non-virtual函数调用之。
*/
}
//#38 通过复合塑膜出has-a或"根据某物实现出"
{
/*
复合有两种情况:
1>has-a
如果你塑造的对象是世界中的某些事物,比如人、物、汽车等等,那么这样的对象属于应用域,
当复合发生在应用域时,表现出has-a的关系。
2>is-implemented-in-terms-of(根据某物实现出)
如果你塑造的对象是为了实现细节上的人工制品,像缓冲区、互斥锁等,这样的对象属于实现域
这样的复合表现出is-implemented-in-terms-of关系。
具体的例子就是,当你想要实现一个set时,你可能需要在类内含一个std::list,因为你不想
自己写list,这样的关系就是is-implemented-in-terms-of,这个set是根据list实现的
这里不用继承的原因是:set不是一个list,list能用的地方set不一定能用。比如list可以插入
重复的值而set不行。
*/
}
//#39 明智而审慎地使用private继承
{
/*
1:private继承意味着is-implemented-in-terms-of。也就是和复合有着异曲同工之妙,然而哪个更好呢?
1>复合可以防止virtual函数被重定义。
2>复合可以解耦两个类,减少编译依赖性。
3>private继承可以实现EBO,也就是使一个“空的”基类真的不占内存。
4>private可以访问到基类protected的内容,复合不行。
2:最后得出的结论:
1>首先考虑复合。
2>真的无法用复合实现,或者真的看重那4byte的字节,那就换成private吧。
*/
}
//#40 明智而审慎地使用多重继承
{
/*
1:多继承常常有很多缺点:
1>比单一继承复杂,可能会造成歧义性,也就是继承的两个基类中有相同名字的函数,那么单单使用
函数名是不知道调用哪一个的。
2>要求基类都来自virtual继承,可是virtual继承是以增加体积,减慢速度,以及复杂的初始化
为成本实现的如果virtual base classes不带任何数据,将是最具使用价值的情况。
(ps:都不带数据了,我不是virtual继承有影响么?就算不是virtual继承也不会有重复东西了啊,
最多就是一个virtual指针)
2:多重继承正当的用途:设计模式中的适配器模式
但是这也是可以转变为复合方式来实现的,所以你需要明智而审慎地决定是否适用多重继承(ps:不建议使用)
*/
}
effective c++ 笔记 (35-40)的更多相关文章
- [Effective JavaScript 笔记]第40条:避免继承标准类
ECMAScript标准库里配备了许多重要的类,如Array,function,以及Date等.扩展这些类生成子类可以方便完成很多工作,但它们的定义具有很多特殊的行为,所以很难写出行为正确的类. Ar ...
- leetcode笔记——35.搜索插入位置 - CrowFea
0.问题描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引.如果目标值不存在于数组中,返回它将会被按顺序插入的位置. 你可以假设数组中无重复元素. 示例 1: 12 输入: [1,3 ...
- 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 笔记]第3章:使用函数--个人总结
前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...
- [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 ...
- Effective STL 笔记 -- Item 6 ~ 7: Container and Object Pointer
Effective STL 笔记 – Item 6 ~ 7: Container and Object Pointer 中间两次笔记被删掉了,简单补一下: Item 3 中提到如果将对象直接放入容器中 ...
随机推荐
- Django之views视图函数
views视图函数属于MTV中逻辑处理的部分视图函数包含着两个对象,HttpRequest对象和HttpResponse对象 一.HttpRequest对象 HttpRequest对象在Django中 ...
- 一个汇编的HelloWorld!
花了一下午时间,感觉最坑的是,书写代码的个数和编译器的坑比较多,还各种版本的编译器! 会让人“眼花缭乱”! 主要代码 将文件保存为*.asm include io32.inc .data ;数据 sr ...
- 用LinkedList
>用LinkedList模拟栈集合MyStack >MyStack测试类 用LinkedList模拟栈集合MyStack import java.util.LinkedList; ...
- chrome浏览器访问Google的插件“谷歌访问插件”以及常用插件
1.解决新版谷歌浏览器无法从该网站添加应用.拓展程序和用户脚本 1.在Google Chrome浏览器的桌面快捷方式上鼠标右键,选择属性(R). 2. 在目标(T)后添加参数 --enable-e ...
- SQLServer 删除表中的重复数据
create table Student( ID varchar(10) not null, Name varchar(10) not null, ); insert in ...
- BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)
Description 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过 ...
- mapreduce设置setMapOutputKeyClass与setMapOutputValueClass原因
一般的mapreduce的wordcount程序如下: public class WcMapper extends Mapper<LongWritable, Text, Text, LongWr ...
- 【转】使用Chrome Frame,彻底解决浏览器兼容问题
本文转自http://www.ryanbay.com/?p=269,感谢该作者的总结 X-UA-Compatible是自从IE8新加的一个设置,对于IE8以下的浏览器是不识别的. 通过在meta中设置 ...
- Azkaban学习之路 (二)Azkaban的安装
安装过程 1.软件介绍 Azkaban Web 服务器:azkaban-web-server-2.5.0.tar.gz Azkaban Excutor 执行服务器:azkaban-executor-s ...
- OpenCV——基本图形绘制(椭圆、圆、多边形、直线、矩形)
//绘制椭圆 void DrawEllipse(Mat img, double angle) { ; ; ellipse(img, Point(WINDOW_WIDTH / , WINDOW_WIDT ...