Effective C++ 35,36,37
35.使公有继承体现 “是一个” 的含义。
共同拥有继承意味着 “是一个”。如 class B:public A。 说明类型B的每个对象都是一个类型A的对象,A比B具有更广泛的概念。而B表示一个更特定的概念。
在C++中不论什么一个參数为基类的函数都能够实际取一个派生类的对象,仅仅有共同拥有继承会如此。对于共同拥有继承,如AB。若有两个函数 一个函数为 void fun1(A &a);还有一个函数为void fun2(B& b);则对于AB的两个对象a。和b。对于 fun1(a)和fun2(b和fun1(b))都是正确的。fun2(a)是错误的。注意仅仅有共同拥有继承才有这个特性,对于私有继承会与此不同。并且这是说 B的对象 "是一个“ A的对象,可是B的数组并非一个A的数组。
使用公有继承常常遇到的问题是对基类适用的规则并不适用于派生类。但公有继承又要求对基类对象适用的不论什么东西都适用于派生类对象,使用公有继承会导致一些错误的设计。
如对于企鹅与鸟,鸟是基类,其有嘴,翅膀等数据成员。另一个飞的成员函数virtual void fly();一開始你觉得鸟有一些属性。且鸟会飞,然后你有觉得企鹅公有继承于鸟,即企鹅是一种鸟,可是问题出现了,企鹅不会飞。
让企鹅直接公有继承于鸟类。这是一个错误的设计。所以你想去改进它,在依旧使用公有继承的前提下。
1.世上有非常多鸟不会飞,于是你将鸟类分成了两种,FlyingBird 和NoFlyingBird,分成会飞和不会飞两种鸟类,这两种鸟类都公有继承于鸟类,而企鹅公有继承于NoFlyingBird。
2.企鹅中依旧有fly()这个函数,可是又一次定义了这个fly函数。使之产生一个执行时错误,使企鹅是鸟,企鹅能飞,可是让企鹅飞的这个操作是错误的。
这是一个执行时才干检測的错误。
当利用一些知识和常识设计一些类并使用公有继承时,可是公有继承却没那么有效,由于最关键的问题是基类中的规则要相同适用于派生类对象,而我们想要用继承实现的对象却有两者不同的规则。而对于这种情况,一般要用”有一个“ 和”用。。
。来实现“这两种关系来实现。
36.区分接口继承和实现继承。
首先,接口是放在public中给外部调用的。而实现是隐藏在private中的内部逻辑。对于类的继承,有时希望派生类仅仅继承成员函数的接口。有时派生类同一时候继承函数的接口和实现。且同意派生类改写实现,有时派生类同一时候继承类的接口与实现。可是不同意改动不论什么东西。
纯虚函数必需要在详细实现类中又一次声明,它们在抽象类中往往未定义。定义纯虚函数的目的在于使派生类只 继承函数的接口。也就是第一种情况,这样的情况非常easy理解。
可是纯虚函数事实上是能够提供定义的。
对于另外一种和第三种情况,继承函数的接口和实现,一般使用虚函数来实现。
而须要改进的地方是。对于一个基类中的虚函数,其有一定的实现。而派生类能够继承这种接口和实现,既能够直接继承基类中这个接口,也能够重写这个接口的实现。
这样非常科学,可是又要一个问题,当一个新的派生类继承这个基类时。因为这个类中使用虚函数做接口,导致新的程序猿忘记了又一次声明这个虚函数并给予新的实现逻辑而去错误的使用虚函数中的默认逻辑而造成了错误。为了提供更安全的基类,使用纯虚函数做接口,让纯虚函数有自己缺省实现,在派生类继承时。直接调用基类纯虚函数的实现:
class A{
public:
virtual void fun() const = 0;
};
void A::fun() const{
cout<<"Class A"<<endl;
}
class B:public A{
public:
virtual void fun() const; };
void B::fun() const{
A::fun();
}
如上所看到的,使用一个纯虚函数。可是带有缺省实现,而派生类继承时就必须又一次声明这个纯虚函数,而对于要调用基类的缺省实现时,除了上面直接调用基类的这个纯虚函数外,还能够通过在基类中的protected中设置一个默认的实现函数,如 void defaultFun() const。而派生类会继承这个默认实现,然后在派生类的又一次定义的虚函数中调用这个默认的实现函数就可以。
这个情况事实上就是另外一种情况,继承函数的接口和实现,且可以改动实现。一般使用虚函数。可是使用带默认操作的纯虚函数会更加安全。安全是一个非常重要的问题,假设不考虑安全性,非常多在Effective C++这本书中讨论的问题都是没有意义的,由于假设你明确之前程序的设定。就知道哪些事情该做,哪些事情不该做,就不会去犯一些错误,可是对于一个程序的开发。不是有一个人完毕的。当你理解自己的设定时,别人却不知道,维护你代码的人任意的做一些他们觉得应该可以做到的安全的事,却由于你之前考虑的不周全而使这些行为极度不安全。所以要认真考虑安全性的问题。写出尽可能完美安全的代码。
对于第三种情况,声明非虚函数。目的在于使派生类继承函数的接口和强制性实现,又因为不应该在派生类中又一次声明和定义基类的非虚函数,所以不会改动非虚函数的实现的。
所以,要理解纯虚函数,简单虚函数和非虚函数声明和功能上的差别。不用操心虚函数的效率问题,由于这真的是小问题,全部基类都应该虚函数。
一些函数不应该在派生类中又一次定义就要将其定义为非虚函数。
37.决不要又一次定义继承而来的非虚函数。
首先,对于又一次定义继承的非虚函数,称为对这个函数的隐藏。这是一种不经常使用的东西,正是由于有这个设定,绝不又一次定义继承而来的非虚函数。
这样做的原因也是非常easy理解的,也是多态的长处:
class A{
public:
void fun() const{
cout<<"Class A"<<endl;
}
};
class B:public A{
public:
void fun() const{
cout<<"Class B"<<endl;
}
};
int main(){
B* b = new B();
A* a = b;
b->fun();
a->fun();
对于以上代码,对同一个对象,也就是b指向的对象,当将其转换为基类指针后,因为其为静态绑定的,其所指向的函数不同,获得了不同的结果。而多态时动态绑定,指向的函数通过虚指针指向同样的地址。
结论是,对于类B的对象,其又一次定义的函数fun()被调用时。其行为是不确定的,而决定因素与对象本身没有关系,而取决于指向它的指针的声明类型,引用也会和指针表现出这种异常行为,这种行为是不合理的。
而从理论上来考虑。对于公有继承意味着 ”是一个“,对于B中又一次定义了A中的实现后,B就不”是一个“ A了。
Effective C++ 35,36,37的更多相关文章
- EC读书笔记系列之16:条款35、36、37、38、39、40
条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...
- Redis 安装,配置,简介,数据类型(一)
Redis 安装 Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你 ...
- python工具--获取盛科交换机端口模块类型,波长,传输距离等信息
交换机端口模块信息对应的OID节点为各厂商私有节点,获取其他厂商信息需要把OID进行替换 1 #! /usr/bin/env python 2 #-*-coding:utf-8-*- 3 import ...
- ethereum/EIPs-155 Simple replay attack protection 35,36
EIP 155:重放攻击保护——防止了在一个以太坊链上的交易被重复广播到另外一条链. 在看椭圆曲线时有提到,与r.s.v中的v相关 不同的共有链定义不同的chainId, 防止同一笔交易在不同的共有链 ...
- 【Warrior刷题笔记】剑指offer 6 24 35. 三道题,让你学会链表递归迭代辅助栈
题目一 从尾到头打印链表 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-l ...
- Effective C++ 之 Item 2:尽量以 const, enum, inline 替换 #define
Effective C++ Chapter 1. 让自己习惯C++(Accustoming Yourself to C++) Item 2. 尽量以 const, enum, inline 替换 #d ...
- .NET程序员不加班——写在《华为工程师猝死,36岁,22月无休》之后
我首先承认,有点标题党.因为这是我这个十年老码农——过了年就整整11年了,o(╥﹏╥)o——的个人观察.经验所得.如果有仍在加班的.NET童鞋,不要打我.一定要打的话,只有一个要求:不要打脸! 写这篇 ...
- [转]9个offer,12家公司,35场面试,从微软到谷歌,应届计算机毕业生的2012求职之路
1,简介 毕业答辩搞定,总算可以闲一段时间,把这段求职经历写出来,也作为之前三个半月的求职的回顾. 首先说说我拿到的offer情况: 微软,3面->终面,搞定 百度,3面->终面,口头of ...
- 9个offer,12家公司,35场面试,从微软到谷歌,应届计算机毕业生的2012求职之路
1,简介 毕业答辩搞定,总算可以闲一段时间,把这段求职经历写出来,也作为之前三个半月的求职的回顾. 首先说说我拿到的offer情况: 微软,3面->终面,搞定 百度,3面->终面,口头of ...
随机推荐
- easyUI 接收Spring Mvc中@ResponseBody中文乱码解决
接触springMVC不够深入,乱码困扰我到深夜,特此留下记忆: @responsebody默认滴是ISO-8859-1 Controller注解参数 @ResponseBody 标注后返回Strin ...
- codevs 1380/HDU 1520 树形dp
1380 没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 回到问题 题目描述 Description Ural大学有N个职员 ...
- js 如何刷新页面
Javascript刷新页面的几种方法(未测试):1 history.go(0)2 location.reload()3 location=location4 location.assign(loca ...
- ConcurrentHashMap 1.8为什么要使用CAS+Synchronized取代Segment+ReentrantLock
大家应该都知道ConcurrentHashMap在1.8的时候有了很大的改动,当然,我这里要说的改动不是指链表长度大于8就转为红黑树这种常识,我要说的是ConcurrentHashMap在1.8为什么 ...
- 【BZOJ4476&JSOI2015】送礼物(二分,RMQ)
ANS明显是有二分性的 二分答案,设二分值为b M(i,j)−m(i,j)j−i+k>b 显然当l<长度<r时,一端是最小值,一端是最大值. 等于l或r的时候因为可能不满足以上性质, ...
- js6:history和navigator对象的学习
原文发布时间为:2008-11-08 -- 来源于本人的百度文章 [由搬家工具导入] <html> <head> <title>js</title> & ...
- android中提示&对话框----ProgressDialog&DatePickerDialog &TimePickerDialog&PopupWindow
ProgressDialog(精度条对话框): 1.直接调用ProgressDialog提供的静态方法show()显示 2.创建ProgressDialog,再设置对话框的参数,最后show()出来 ...
- formal parameter
formal parameter : [3.16] object declared as part of a function declaration or definition that acqui ...
- hdu 3986(最短路变形好题)
Harry Potter and the Final Battle Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65536/6553 ...
- HttpModel 和 HttpHandle
页面的请求过程: HttpRequest-> inetinfo.exe-> aspnet_isapi.dll-> Http pipeline(命名管道)-> aspnet_wp ...