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)
const = 0;

};

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:不建议使用)

*/

}

时间: 2024-08-25 09:11:53

effective c++ 笔记 (35-40)的相关文章

Effective C++笔记06:继承与面向对象设计

关于OOP 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtual或non-virtual或pure-virtual. 3,成员函数和其他语言特性的交互影响:缺省参数值与virtual函数有什么交互影响?继承如何影响C++的名称查找规则?设计选项有如些?如果class的行为

Effective C++笔记:构造/析构/赋值运算

条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函数时,编译器会给我们构造默认的. 当成员变量里有const对象或引用类型时,编译器会不能合成默认的拷贝赋值函数:当一个基类把它的拷贝赋值函数定义为private时,它的派生类也不无生成默认的拷贝赋值函数,因为它无法完成基类成份的赋值. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 将拷贝构

Effective c++(笔记)之继承关系与面向对象设计

1.公有继承(public inheritance) 意味着"是一种"(isa)的关系 解析:一定要深刻理解这句话的含义,不要认为这大家都知道,本来我也这样认为,当我看完这章后,就不这样认为了. 公有继承可以这样理解,如果令class D以public 的形式继承了class B ,那么可以这样认为,每一个类型为D的对象同时也可以认为是类型为B的对象,但反过来是不成立的,对象D是更特殊化更具体的的概念,而B是更一般化的概念,每一件事情只要能够施行于基类对象身上,就一定可以应用于派生类对

笔记3-5: pread/pwrite函数

原子操作 一.添写到文件 早期的UNIX的open函数里面,不支持O_APPEND的选项.所以要追写到文件结尾处,必须先利用lseek把文件偏移量移到文件的结尾处,再进行write操作. 如果当前进程A刚执行完lseek后,系统进程调度作用切换到了另一个进程B,进程B对同一个文件进行了写操作.进程B写文件后,系统再把控制权交还进程A,这时进程A所指向的文件偏移量已经不再是最结尾处,如果写入数据,就会覆盖到进程B刚才写入的数据. UNIX提供一个方法使追加写入成为一个原子操作,该方法是在open一

Effective C++ Item 35 考虑 virtual 函数以外的实现

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.virtual 函数版本 class GameCharacter{ public: virtual int healthValue() const; //返回人物的健康指数, derived classes 可重新定义它 }; 2.使用 non-virtual interface 手法,那是 Template Method 设计模式的一种特殊形式. 让客户通过 public non-v

Effective c++(笔记) 之 类与函数的设计声明中常遇到的问题

1.当我们开始去敲代码的时候,想过这个问题么?怎么去设计一个类? 或者对于程序员来说,写代码真的就如同搬砖一样,每天都干的事情,但是我们是否曾想过,在c++的代码中怎么样去设计一个类?我觉得这个问题可比我们"搬砖"重要的多,大家说不是么? 这个答案在本博客中会细细道来,当我们设计一个类时,其实会出现很多问题,例如:我们是否应该在类中编写copy constructor 和assignment运算符(这个上篇博客中已说明),另外,我们是让编写的函数成为类的成员函数还是友元还是非成员函数,

Effective C++笔记05:实现

条款26:尽可能延后变量定义式的出现时间 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本. 所以我们应该在定义对象时,尽可能的延后,甚至直到非得使用该变量前一刻为止,应该尝试延后这份定义直到能够给它初值实参为止. 这样做的好处是:不仅可以避免构造(析构)非必要对象,还可以避免无意义的default构造行为. 遇到循环怎么办?此时往往我

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

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

Effective c++(笔记)----类与函数之实现

上篇博客中集中说明了在设计一个类的时候常遇到的问题,当然博客中还夹杂着我随时想到的一些知识,发现自己写博客没很多人写的好,可能是自己语言不会组织,要么就是写的东西大家不愿意看,反正是有这方面的专业问题或者博客中有什么明显的错误和问题,大家提出来,我也好改进哈! 回归正题,这篇博客就大概的把Effective c++中类与函数这节看到的知识点做个笔记. 设计好一个类后,自己就要去实现这个类(实现类中的成员函数.友元.非成员函数等) 可能大家会遇到以下问题 1.在类的成员函数中,尽量避免返回内部数据

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

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用