Effective C++:规定34:区分接口继承和实现继承
(一个)
class Shape {
public:
virtual void draw() const = 0;
virtual void error(const string& msg);
int objectID() const;
};
class Rectangle : public Shape {...};
class Ellipse : public Shape {...};
公有继承的概念看似简单。似乎非常轻易就浮出水面。然而细致审度之后,我们会发现公有继承的概念实际上包括两个相互独立的部分:函数接口的继承和函数实现的继承。二者之间的区别恰与函数声明和函数实现之间相异之处等价。成员函数的接口总是被继承,由于public继承意味is-a。
pure virtual 函数两个突出特征:(1)必须被不论什么“继承了它们”的具象class又一次声明。(2)它们在抽象class中通常未定义。
(二)
声明一个pure
virtual函数的目的是为了让derived class仅仅继承函数接口。我能够为它提供一份实现代码,但调用它的唯一途径是“调用时明白指出期class的名称”。
Sharp* ps1 = new Rectangle;
ps1->draw();
Sharp* ps2 = new Rectangle;
ps2->draw();
ps1->Shape::draw();//调用Shape的draw
ps2->Shape::draw();
(三)
声明impure
virtual函数的目的。是让derived classes继承该函数的接口和缺省实现。
同意impure
virtual函数同一时候指定函数声明和函数缺省行为,却有可能造成危急。
class Airport {...};
class Airplane {
public:
virtual void fly(const Airport& destination);
};
void Airplane::fly(const Airport& destination) {
//缺省代码,将飞机飞至指定目的地
}
class ModelA : public Airplane {...};
class ModelB : public Airplane {...};
class ModelC : public Airplane {
...//未声明fly函数,但它并不希望缺省飞行
};
Airport PDX(...);
Airplane* pa = new ModelC;
...
pa->fly(PDX); //未说出“我要的情况下就继承了该缺省行为,酿成大灾难”
这个程序试图用ModelA和ModelB的飞行方式来飞ModelC。
问题不在Airplane::fly()有缺省行为,而在于ModelC在未明白说出“我要”的情况下就继承了该缺省行为。我们能够做到“提供缺省实现给derived classes。但除非它们明白要求,否则免谈”。
解决的方法(1):此间伎俩在于切断“virtual
函数接口”和其“缺省实现”之间的连接。以下是一种做法:
class Airplane {
public:
virtual void fly(const Airport& destination) = 0;
...
protected:
void defaultFly(const Airport& destination);
};
void Airplane::defaultFly(const Airport& destination) {
//缺省行为,将飞机飞至目的地
}
fly已被改成为一个pure
virtual函数,仅仅提供飞行接口。缺省行为以defaultFly出如今Airplane class中。
若想使用缺省实现(比如ModelA和ModelB)。能够在fly中对defaultFly做一个inline调用:
class ModelA: public Airplane {
public:
virtual void fly(const Airport& destination) {
defaultFly(destination);
}
...
};
class ModelB: public Airplane {
public:
virtual void fly(const Airport& destination) {
defaultFly(destination);
}
...
};
如今ModelC不可能意外继承不对的fly实现代码了。由于Airplane中的pure
virtual函数迫使ModelC必须提供自己的fly版本号:
class ModelC: public Airplane {
public:
virtual void fly(const Airport& destination);
...
};
void ModelC::fly(const Airport& destination) {
//将C型飞机飞至指定的目的地
}
像这种话,这个方法并不是安全无虞。程序猿还是可能由于剪贴(copy-and-paste)代码而招来麻烦,但它比原来的设计值得依赖。
有些人反对以不同的函数分别提供接口和缺省实现,向上述的fly和defaultFly那样。
所以我们想出了以下这样的解决的方法:
解决的方法(2):
我们能够利用“pure
virtual函数必须在derived class中又一次声明。但它们能够拥有自己的实现”这一事实。
以下是Airplane继承体系怎样给pure virtual函数一份定义:
class Airplane {
public:
virtual void fly(const Airport& destination) = 0;
...
};
void Airplane::fly(const Airport& destination) // pure virtual 函数实现 {
//缺省行为,将飞机飞至指定目的地
}
class ModelA: public Airplane {
public:
virtual void fly(const Airport& destination) {
Airplane::fly(destination);
}
};
class ModelB: public Airplane {
public:
virtual void fly(const Airport& destination) {
Airplane::fly(destination);
}
};
class ModelC: public Airplane {
public:
virtual void fly(const Airport& destination)
...
};
void ModelC::fly(const Airport& destination) {
// 将C型飞机飞至指定目的地
}
(四)
假设成员函数是个non-virtual函数,意味着它并不打算在derived classes中有不同的行为。non-virtual 成员函数所表现的不变性凌驾其特异性,不管derived
class变得多么特异化。它的行为都不能够改变。
声明non-virtual函数的目的是为了令derived
class继承函数的接口及一份强制性实现。
class Shape {
public:
...
int objectID() const;
};
来看Shape::objectID的声明:能够想做是“每一个Shape对象都有一个用来产生对象识别码的函数:此识别码总是採用同样计算方法,该方法由Shape::objectID的定义式决定,不论什么derived
class都不应该尝试改变其行为”。
请记住:
1. 接口继承&实现继承不同。在public继承之下。derived classes总是继承base
class的接口。
2. Pure virtual函数仅仅详细指定接口继承。
3. Impure virtual函数详细指定接口继承及缺省实现继承。
4. non-virtual函数详细指定接口继承以及强制性实现继承。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
Effective C++:规定34:区分接口继承和实现继承的更多相关文章
- Effective C++ Item 34 区分接口继承与实现继承
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 关联条款 Item 36 接口继承和实现继承不同.在 public 继承下, derived ...
- 读书笔记 effective c++ Item 34 区分接口继承和实现继承
看上去最为简单的(public)继承的概念由两个单独部分组成:函数接口的继承和函数模板继承.这两种继承之间的区别同本书介绍部分讨论的函数声明和函数定义之间的区别完全对应. 1. 类函数的三种实现 作为 ...
- Effective C++ 34 区分接口继承和实现继承
public继承从根本上讲,有两部分:接口继承和实现继承.两者之前的区别很像函数声明与函数定义. 具体设计中,会呈现三种形式:derived class只继承成员函数的接口(纯虚函数):derived ...
- Effective C++ -----条款34:区分接口继承和实现继承
接口继承和实现继承不同.在public继承之下,derived classes总是继承base class的接口. pure virtual函数只具体指定接口继承. 简朴的(非纯)impure vir ...
- 条款34:区分接口继承和实现继承(Different between inheritance of interface and inheritance of implemenation)
NOTE: 1.接口继承和实现继承不同.在public继承之下,derived classes总是继承base class的接口. 2.pure virtual 函数只具体指定接口继承及缺省实现继承. ...
- [EffectiveC++]item34:区分接口继承和实现继承
[EffectiveC++]item34:区分接口继承和实现继承
- 【C++】Item34.区分接口继承和实现继承
区分接口继承和实现继承 类包含的成员函数种类 1.静态函数 2.非静态函数 2.1 普通函数(非虚) non-virtual 2.2 虚函数 2.2.1 纯虚函数 pure-virtual 2.2.2 ...
- 读书笔记_Effective_C++_条款三十四:区分接口继承和实现继承
这个条款书上内容说的篇幅比较多,但其实思想并不复杂.只要能理解三句话即可,第一句话是:纯虚函数只继承接口:第二句话是:虚函数既继承接口,也提供了一份默认实现:第三句话是:普通函数既继承接口,也强制继承 ...
- C++接口继承与实现继承的区别和选择
1.接口继承与实现继承的区别 <Effective C++>条款三十四:区分接口继承和实现继承中介绍的比较啰嗦,概括地说需要理解三点: (1)纯虚函数只提供接口继承,但可以被实现: (2) ...
随机推荐
- mysql5.6设置主从报错1236,Increase max_allowed_packet on master,原因却是Binlog偏移量不对
在试Mysql5.6,搭了个主从: CHANGE MASTER TO MASTER_HOST='1.2.3.4', master_user='slave', master_password='xxxq ...
- SQL Server 日期相关
原文:SQL Server 日期相关 原帖出处:http://blog.csdn.net/dba_huangzj/article/details/7657979 对于开发人员来说,日期处理或许简单,或 ...
- 为大型数据文件每行只能产生id
为大型数据文件每行只能产生id 4个主要思路: 1 单线程处理 2 普通多线程 3 hive 4 Hadoop 搜到一些參考资料 <Hadoop实战>的笔记-2.Hadoop输入与输出 h ...
- SQL Server 数据库索引
原文:SQL Server 数据库索引 一.什么是索引 减少磁盘I/O和逻辑读次数的最佳方法之一就是使用[索引] 索引允许SQL Server在表中查找数据而不需要扫描整个表. 1.1.索引的好处: ...
- swift学习笔记(七)自己主动引用计数
与Object-c一样,swift使用自己主动引用计数来跟踪并管理应用使用的内存.当实例不再被使用时,及retainCount=0时,会自己主动释放是理所占用的内存空间. 注:引用计数仅适用于类的实例 ...
- android控件 下拉刷新pulltorefresh
外国人写的下拉刷新控件,我把他下载下来放在网盘,有时候訪问不了github 支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.GridV ...
- php学习之道:mysql SELECT FOUND_ROWS()与COUNT(*)使用方法差别
在mysql中 FOUND_ROWS()与COUNT(*)都能够统计记录.假设都一样为什么会有两个这种函数呢.以下我来介绍SELECT FOUND_ROWS()与COUNT(*)使用方法差别 SELE ...
- HTML5分析实战WebSockets基本介绍
HTML5 WebSockets规范定义了API,同意web使用页面WebSockets与远程主机协议的双向交流. 介绍WebSocket接口,并限定了全双工通信信道,通过套接字网络.HTML5 We ...
- JQuery之初探
软考过后又进入了紧张的B/S学习阶段,因为自己的进度比較慢,所以更要加进学习.如今就来总结下JQuery的一些基础知识: JQuery定义 jQuery是一套跨浏览器的JavaScript库,简化HT ...
- 对Unity3d C#手动处理异常产生
System.AppDomain.CurrentDomain.UnhandledException += new System.UnhandledExceptionEventHandler(_OnUn ...