《Effective C++》继承与面向对象设计
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函数比较,它提供了某些有趣的弹性:
- 同意任务类型的不同实体可以有不同的健康计算函数。
某已知任务的健康指数计算函数可以在运行期变更。
总结:①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身上,那么:
- 适用于B对象的每一件事,也适用于D对象,因为每一个D对象都是一个B对象。
- 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++》继承与面向对象设计的更多相关文章
- Effective C++ —— 继承与面向对象设计(六)
条款32 : 确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public inheritance(公开继承)意味“is-a”(是一种)的关系.请务必牢记.当 ...
- Effective C++ -- 继承和面向对象设计
32.确保你的public继承了模is-a关系 public继承意味着is-a关系(里氏替换原则),一切适用于基类也适用于派生类. 矩形继承正方形问题: 可实施与矩形的操作无法实施与正方形 在编程领域 ...
- Effective C++ ——继承与面向对象设计
条款32:确定你的public继承塑模出is-a关系 以public继承的类,其父类的所有的性质都应该使用与子类,任何需要父类的地方都应该能用子类来代替,任何子类类型的对象也同时是父类的: class ...
- EffectiveC++ 第6章 继承与面向对象设计
我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter 6 继承与面向对象设计 Inheritance and ...
- Effective C++(20) 继承与面向对象设计
本文主要参考<Effective C++ 3rd>中的第六章部分章节的内容. 关注的问题集中在继承.派生.virtual函数等.如: virtual? non-virtual? pure ...
- Effective C++: 06继承与面向对象设计
32:确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public继承表示的是"is-a"(是一种)的关系. 如果令class D以pub ...
- Effective C++ 6.继承与面向对象设计
//条款32:确定你的public继承塑模出is-a关系 // 1.public继承意味着is-a的关系,适用在基类上的方法都能用于派生类上. //条款33:避免遮掩继承而来的名称 // 1.在pub ...
- Effective C++笔记:继承与面向对象设计
关于OOP 博客地址:http://www.cnblogs.com/ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private ...
- Effective C++笔记(六):继承与面向对象设计
参考:http://www.cnblogs.com/ronny/p/3756494.html 条款32:确定你的public继承塑模出is-a关系 “public继承”意味着is-a.适用于base ...
- 【Effective C++】继承与面向对象设计
关于OOP 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtu ...
随机推荐
- vlunhub靶场之EMPIRE: LUPINONE
准备: 攻击机:虚拟机kali.本机win10. 靶机:EMPIRE: LUPINONE,网段地址我这里设置的桥接,所以与本机电脑在同一网段,下载地址:https://download.vulnhub ...
- 3.CBV视图之csrf补充
CBV使用csrf装饰器关闭/开启 csrf验证,直接在函数上加装饰器无效的 #方法1 from django.views import View from django.views.decorato ...
- $_SERVER["REQUEST_URI"],在 PHP 众多预定义服务器变量中,$_SERVER["REQUEST_URI"] 算是经常用到的,但是这个变量只有 apache 才支持
例如访问:http://localhost/index.php?app=lunbo获取到的$_SERVER["REQUEST_URI"]为"/index.php?app= ...
- JAVA的File对象
文件 1.File对象 java封装的一个操作文件及文件夹(目录)的对象.可以操作磁盘上的任何一个文件和文件夹. 2.创建文件 方式一:根据路径构建一个File对象new File(path) // ...
- 畅联新设备接入情况:新增威隆NB烟感
双美接入,应该是电信AEP平台的. ---------------------------------------------------------------------------------- ...
- Oracle数据库的导出和导入
本次数据库的导入导出操作是导出公司环境的Oracle数据库,再导入本地数据库,采用impdp和expdp命令进行导入导出操作. 一.导出52数据库 1.用system用户登录到数据库,查看是否有创建d ...
- 10 | Kubernetes一键部署利器:kubeadm
你好,我是张磊.今天我和你分享的主题是:Kubernetes一键部署利器之kubeadm. 通过前面几篇文章的内容,我其实阐述了这样一个思想:要真正发挥容器技术的实力,你就不能仅仅局限于对Linux容 ...
- Go语言核心36讲42-----io包中接口的好处与优势
我们在前几篇文章中,主要讨论了strings.Builder.strings.Reader和bytes.Buffer这三个数据类型. 知识回顾 还记得吗?当时我还问过你"它们都实现了哪些接口 ...
- Go语言核心36讲19
你好,我是郝林,今天我们继续分享go语句执行规则的内容. 在上一篇文章中,我们讲到了goroutine在操作系统的并发编程体系,以及在Go语言并发编程模型中的地位和作用等一系列内容,今天我们继续来聊一 ...
- KubeEdge架构问题汇总
Q1 :KubeEdge云和边的数据协同有什么优势? A : K8s的原生架构中, Node (Kubelet) 是通过List-watch机制主动与Master通信.List-watch机制有几个 ...