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) ...
随机推荐
- Direct3D 使用质地
关于使用质地 1 创建纹理 2 纹理寻址模式 3 纹理过滤 1 创建纹理 <1> D3DXCreateTexture功能 创建一个空的纹理. HRESULT D3DXCreateText ...
- UFLDL接听教程练习(来自编码器和矢量编程疏)
最近想在深入学习研究,开始看UFLDL(unsuprisedfeature learning and deep learning)教程了.特将课后习题答案放在这里,作为一个笔记. 笔记: 1:自编码算 ...
- Codeforces Round #256 (Div. 2)——Multiplication Table
题目链接 题意: n*m的一个乘法表,从小到大排序后,输出第k个数 (1 ≤ n, m ≤ 5·105; 1 ≤ k ≤ n·m) 分析: 对于k之前的数,排名小于k:k之后的数大于,那么就能够採用 ...
- STL源代码分析--迭代摘要、迭代器失效汇总
Vector 1.内部数据结构:连续存储,比如数组. 2.随机訪问每一个元素,所须要的时间为常量. 3.在末尾添加或删除元素所需时间与元素数目无关,在中间或开头添加或删除元素所需时间随元素数目呈线性变 ...
- JS封深入了解
1. javascript 语言理解闭包 js变量的范围分成两个:全局变量.局部变量.在全局变量的函数外声明变量,内部功能可以直接调用全局变量.声明变量里面的函数必须使用var 命令,否则,它里面的函 ...
- 5.非关系数据库(Nosql)它mongodb:创建一个集合,导出和导入备份, 数据恢复,进出口
1 固定集合 固定集合值得是事先创建并且大小固定的集合 2 固定集合的特征:固定集合非常像环形队列.假设空间不足,最早文档就会被删除,为新的文档腾出空间.一般来说.固定集合适用于不论什么想要自己 ...
- Android清除缓存功能来实现
我们都知道在Android的设置->应用程序中能够查看应用程序的相关信息,当中有一个功能是清除缓存. 如图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...
- 60分钟Python快速学习(转)
60分钟Python快速学习(给发哥一个交代) 阅读目录 第一步:开发环境搭建: 第一个Python功能:初识Python 02.Python中定义变量不需要数据类型 03.在Pythod中定义方法 ...
- Building a RESTful Web Service(转)
Building a RESTful Web Service This guide walks you through the process of creating a "hello wo ...
- leetcode 之 Unique Paths
Unique Paths A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagra ...