Item 32:确定你的public继承塑膜出is-a的关系

如果你令class D以public继承class B,你便是告诉编译器说,每一个类型为D的对象同时也是一种B对象,反之如果你需要一个D对象,B对象无法效劳,因为虽然每个D对象都是一个B对象,反之不成立。

**总结:**public继承意味着is-a,适用于base classes身上的每一件事也适用于derived classes身上,因为没一个derived class都是一个base class对象。


Item 33:避免遮掩继承而来的名称

总结:①derived class内的名称会遮掩base class内的名称,在public继承下从来没有人希望如此。

②为了让被遮掩的名称在见天日,可使用using声明式或者转义函数。


Item 34:区分接口继承和实现继承

总结:①接口继承和实现继承不同,在public继承之下,derived class总是继承base class的接口。

②pure virtual函数只具体指定接口继承。

③impure virutal函数具体指定接口继承及缺省实现继承。

④non-virtual函数具体指定接口继承以及强制性实现继承。


Item 35:考虑virtual函数以外的其他选择

藉由non-virtual interface首发实现template method模式。

这个流派主张virtual函数应该几乎总是private,这个流派的拥护者建议,较好的设计是保留healthvalue为public成员函数,但让它成为non-virtual,并调用一个private virtual函数进行实际工作。

class GameCharacter{
public:
int healthValue() const
{
int retval=dohealthValue();//做一些真正的工作
return retval;
}
private:
virtual int dohealthValue()const//派生类可重新定义它
{
...//缺省算法,计算健康函数
}

这一基本设计,也就是令客户通过public non-virtual成员函数间接调用private virtual函数,称为non-virtual interface(NVI)手法。它是所谓template method设计模式(与C++templates 并无关系)的一个独特表现形式,我把这个non-virtual函数称为virtual函数的外覆器(wrapper)。

优点:可以确保外覆器在一个virtual函数被调用之前设定好场景,并且在调用之后清理场景。“事前工作做”可包含锁定互斥器。制造运转日志及录像,验证class约束条件等,“事后工作”可以包括互斥器,解除锁定,验证函数的事后条件,再次验证class约束条件等等,如果让客户直接调用virtual函数,则没有这个优点。

由function pointer实现strategy模式
class GameCharacter;//前置声明
int defaultHealthcalc(cosnt GameCharacter&gc);
class GameCharacter{
public:
typedef int (*HealthcalcFunc)(const GameCharacter&);
explict GameCharacter(HealthcalcFunc hcf=defaultHealthCalc):healthFUnc(hcf){}
int healthValue()const
{ return HealthFunc(*this);}
private:
HealthCalcFunc healthFunc;
}
}

这个做法是常见的strategy设计模式的简单应用,拿它和“基于GameCharacter”继承体系内之virtual函数比较,它提供了某些有趣的弹性:

  1. 同意任务类型的不同实体可以有不同的健康计算函数。
  2. 某已知任务的健康指数计算函数可以在运行期变更。

    总结:①virtual函数的替代方案包括NVI手法和Strategy设计模式的多种形式,NVI手法是一个特殊形式的template method设计模式。

    ②将机能从成员函数移到class外部函数,带来的一个缺点是,非成员函数无法访问class的non-public成员。


Item36:绝不重定义继承来的non-virtual函数

item32说过所谓的public继承意味着is-a的关系,item34则指出为什么在class内声明一个non-virtual函数会为该class建立一个不变性,凌驾于特异性,如果你将这两个观点施行于两个classB和D以及non-virtual成员函数B:mf身上,那么:

  1. 适用于B对象的每一件事,也适用于D对象,因为每一个D对象都是一个B对象。
  2. B的derived class一定会继承mf的接口和实现,因为mf是B的一个non-virtual函数。

    现在,如果D重新定义mf,你的设计便出现矛盾,如果D真的有必要实现出与B不同的mf,并且如果没一个D对象-不管有多么特化-真的必须使用D所提供的mf实现代码,那么“每一个D都是一个B”就不是真,既然如此,D就不该以public形式继承B。另一方面,如果D真的必须以public形式继承B,并且如果D真的需要实现出与B不同的mf,那么mf就无法为B反应出“不变性凌驾于特异性”的性质,既然这样mf应该什么为virtual函数,最后,如果每个D真的是一个B,并且如果mf真的为B反映出“不变性凌驾于特异性”的性质,那么D就不需要重新定义mf,而且它也不应该尝试这么做,不论是哪一种观点:任何情况下都不应该重新定义一个继承而来的non-virtual函数。

Item38:通过符合塑模出has-a或者“根据某物实现出”


Item39:明智而审慎地使用private继承

总结:①private继承意味着is-implementated-in-terms-of(根据某物实现出),它通常比private继承1 复合的级别低,但是当derived class需要访问protected base class的成员,或者重新定义继承而来的virtual函数时候,这么设计是合理的。

②和复合不同,private继承可以造成empty base class最优化,这对于致力于“对象尺寸最小化”的程序库开发者来说,可能很重要。


Item40:明智而审慎地使用多重继承

总结:①多重继承比单一继承更复杂,它可能导致新的歧义性,以及对virtual继承的需要。

②virtual继承会增加大小,速度,初始化复杂度等成本。如果virtual base classes不带任何数据,将是最具有使用价值的情况。

③多重继承的确有正常用途,其中一个情节涉及“public 继承某个interface class”和“private 继承自某个协助实现的class”的俩相组合。

《Effective C++》继承与面向对象设计的更多相关文章

  1. Effective C++ —— 继承与面向对象设计(六)

    条款32 : 确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public inheritance(公开继承)意味“is-a”(是一种)的关系.请务必牢记.当 ...

  2. Effective C++ -- 继承和面向对象设计

    32.确保你的public继承了模is-a关系 public继承意味着is-a关系(里氏替换原则),一切适用于基类也适用于派生类. 矩形继承正方形问题: 可实施与矩形的操作无法实施与正方形 在编程领域 ...

  3. Effective C++ ——继承与面向对象设计

    条款32:确定你的public继承塑模出is-a关系 以public继承的类,其父类的所有的性质都应该使用与子类,任何需要父类的地方都应该能用子类来代替,任何子类类型的对象也同时是父类的: class ...

  4. EffectiveC++ 第6章 继承与面向对象设计

    我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter 6 继承与面向对象设计 Inheritance and ...

  5. Effective C++(20) 继承与面向对象设计

    本文主要参考<Effective C++ 3rd>中的第六章部分章节的内容. 关注的问题集中在继承.派生.virtual函数等.如: virtual? non-virtual? pure ...

  6. Effective C++: 06继承与面向对象设计

    32:确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public继承表示的是"is-a"(是一种)的关系. 如果令class D以pub ...

  7. Effective C++ 6.继承与面向对象设计

    //条款32:确定你的public继承塑模出is-a关系 // 1.public继承意味着is-a的关系,适用在基类上的方法都能用于派生类上. //条款33:避免遮掩继承而来的名称 // 1.在pub ...

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

    关于OOP 博客地址:http://www.cnblogs.com/ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private ...

  9. Effective C++笔记(六):继承与面向对象设计

    参考:http://www.cnblogs.com/ronny/p/3756494.html 条款32:确定你的public继承塑模出is-a关系 “public继承”意味着is-a.适用于base ...

  10. 【Effective C++】继承与面向对象设计

    关于OOP 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtu ...

随机推荐

  1. CSAPP实验attacklab

    attacklab 实验报告和答案文件都在 https://github.com/thkkk/attacklab

  2. 删除数组里含有a的元素,并且将null值放在后面

    想去掉里面含有a的元素,并将null放在后面.放在后面就是往后移,其他值往左移 1 public static void main(String[] args) { 2 //自定义的一个数组 3 St ...

  3. Vue学习之--------Scoped样式(2022/8/1)

    1.场景 一个页面开发团队进行页面的开发设计.无可避免的会发生样式选择器命名的重复(id的重复.class的重复等).这样间接导致的后果就是.自己的页面样式好好的.在整合一起的时候.可能就会发生样式的 ...

  4. linux重置密码

    方法一: 进入grub菜单界面 按e键 在linux开头的行按ctrl+e 或者end跳到行尾,输入rd.break 按ctrl+x mount -o remount,rw /sysroot chro ...

  5. Docker中数据卷(Volume)的使用

    数据卷有两种形式,一种是容器中的某个目录,它可以被别的容器引用,只要有一个容器引用了这个数据卷,数据就不会被删除:另一种数据卷是将容器中的数据卷和宿主机的目录进行挂载. 数据卷可以在多个容器之间共享, ...

  6. FHQ Treap 详解

    鲜花 一些鲜花放在前面,平衡树学了很久,但是每学一遍都忘,原因就在于我只能 70% 理解 + 30% 背板子,所以每次都忘.这次我采取了截然不同的策略,自己按照自己的理解打一遍,大获成功(?),大概打 ...

  7. Ubuntu 下安装 redis 并且设置远程登陆和密码

    安装redis sudo apt-get install -y redis-server 更改配置 sudo vim /etc/redis/redis.conf 如果不知道怎么找 直接在命令行模式下输 ...

  8. WinDBG详解进程初始化dll是如何加载的

    一:背景 1.讲故事 有朋友咨询个问题,他每次在调试 WinDbg 的时候,进程初始化断点之前都会有一些 dll 加载到进程中,比如下面这样: Microsoft (R) Windows Debugg ...

  9. Linux网络通信(TCP套接字编写,多进程多线程版本)

    预备知识 源IP地址和目的IP地址 IP地址在上一篇博客中也介绍过,它是用来标识网络中不同主机的地址.两台主机进行通信时,发送方需要知道自己往哪一台主机发送,这就需要知道接受方主机的的IP地址,也就是 ...

  10. 「工具推荐」golang 代码可视化工具 go-callvis

    「工具推荐」go-callvis go-callvis是相对 以图片的形式展示了go程序的调用关系,这个工具在看复杂项目时尤其有用. 亲测,借助它看祖传golang代码,头痛好多了. 安装 go ge ...