C++中的接口继承和实现继承
很多人认为,C++中是不存在接口继承的,只有Java、C#这类语言才提供了相应的语法支持。
但是,如同鲁迅说过的某句名言:世上本没有接口继承,用的人多了,才有了接口继承。C++中依然可以实现接口继承,只是形式上稍有不同罢了。
C++中的继承基于一个事实:父类定义的成员函数会一直被子类继承(包括被子类隐藏的部分)。
而父类中提供的函数可以有三种:1)普通成员函数 2)普通虚函数 3)纯虚函数。这三种函数类型代表了三种继承设计模式。
一个简单的实例代码如下:
01 |
class Shape |
02 |
{ |
03 |
public : |
04 |
virtual void Draw() = 0; |
05 |
virtual int GetError(); |
06 |
int GetId(); |
07 |
}; |
08 |
09 |
class Rectangular : public Shape |
10 |
{ |
11 |
//... |
12 |
}; |
13 |
14 |
class Circle : public Shape |
15 |
{ |
16 |
//... |
17 |
}; |
普通成员函数由父类声明且实现,子类应继承接口以及强制性的实现。
这几乎是最常见的一种函数类型,代表了典型的”is-a”继承设计模式。
ps:所谓的”is-a”设计模式,指的是”everything that applies to base classes must also apply to derived classes”
示例中,函数GetId严格遵守”is-a”模式。因为每个子类本质都是一个Shape对象,都有一个唯一的ID
普通虚函数可以在父类中有默认的实现,而这个默认实现可以由子类继承。
子类也可以选择重写虚函数以实现多态性。
所以,普通虚函数在继承设计中表示派生类必须支持此接口,但是否重写,由派生类自己决定。
如同每个子类对象都应该有一个报错函数。但是函数可以使用父类提供的默认实现(提示简单的出错信息,然后清理资源),也可以选择自己实现(每个子类有自己的错误语义)
纯虚函数会使得父类自动成为不可实例化的抽象类。而且每个继承的子类必须强制自行重写。
所以,纯虚函数表示子类继承父类的函数接口,并且必须自己具体实现该函数。
即从这个角度上看,纯虚函数代表的就是接口继承。
实例代码中,父类将Draw声明为纯虚函数。这表明每个具体的子类都应该有Draw函数,并且需要自己实现(每个具体子类的Draw实现应是不同的)。
对于纯虚函数,有一个有意思的特性:纯虚函数可以有实现代码
之所以说这个特性有意思,是因为拥有纯虚函数的类不能实例化并且纯虚函数指定的是接口继承,子类仍然需要自己实现函数。
这就引发了一个问题:如何调用这个纯虚函数的默认实现版本?解决的方法是显式调用
1 |
Shape* p = new Rectangular; |
2 |
assert (p != NULL); |
3 |
4 |
// invoke defaulat implementation of the pure-virtual function |
5 |
p->Shape::Draw(); |
6 |
7 |
// doing something later |
8 |
delete p; |
那么这种让人觉得操蛋的trick有没有什么应用呢?
假设你有一个父类F,定义了一个普通虚函数,子类A,B都使用默认的虚函数实现。但是某天你需要增加一个新的子类C,但是这个子类不能使用默认的实现,必须重写。
不幸的是,你忘了重写这个函数,所以编译器为你调用了默认实现,于是意外的结果让你蛋碎了一地。
很明显,使用带有实现的纯虚函数就可以解决这个问题。纯虚函数会强制要求你重写虚函数,而你也可以在需要默认实现时通过显式调用完成相应工作。
不过需要这种trick的情况相当罕见,而且多半是设计出了问题或者完全可以人为避免。
C++中的接口继承和实现继承的更多相关文章
- 第五节:详细讲解Java中的接口与继承
前言 大家好,给大家带来详细讲解Java中的接口与继承的概述,希望你们喜欢 什么是接口(interface) 接口中的方法都是抽象方法,public权限,全是抽象函数,不能生成对象 interface ...
- 【Java面试题】60 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法?
接口可以继承接口.抽象类可以实现(implements)接口,抽象类可以继承具体类.抽象类中可以有静态的main方法. 问: 抽象类是否可继承实体类 (concrete class) 答: 抽象类是 ...
- Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现
前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...
- Java中的集合(六)继承Collection的Set接口
Java中的集合(六)继承Collection的Set接口 一.Set接口的简介 Set接口和List接口都是继承自Collection接口,它与Collection接口中功能基本一致,并没有对Col ...
- Java中的集合(五)继承Collection的List接口
Java中的集合(五)继承Collection的List接口 一.List接口简介 List是有序的Collection的,此接口能够精确的控制每个元素插入的位置.用户能够根据索引(元素在List接口 ...
- Java中的集合(三)继承Collection的Queue接口
Java中的集合(三)继承Collection的Queue接口 一.Queue介绍 Queue接口继承自Collection接口,是Java中定义的一种队列数据结构,元素是有序的(按插入顺序排序),先 ...
- Effective C++ 34 区分接口继承和实现继承
public继承从根本上讲,有两部分:接口继承和实现继承.两者之前的区别很像函数声明与函数定义. 具体设计中,会呈现三种形式:derived class只继承成员函数的接口(纯虚函数):derived ...
- c++ 接口继承和实现继承
所谓接口继承,就是派生类只继承函数的接口,也就是声明:而实现继承,就是派生类同时继承函数的接口和实现. 我们都很清楚C++中有几个基本的概念,虚函数.纯虚函数.非虚函数. 虚函数: 虚函数是指一个类中 ...
- JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)
实现线程并发有两种方式:1)继承Thread类:2)实现Runnable接口. 线程基础 1)程序.进程.线程:并行.并发. 2)线程生命周期:创建状态(new一个线程对象).就绪状态(调用该对象的s ...
- pure virtual、impure virtual、non-virtual函数的接口继承和实现继承
1.abstract class 拥有pure virtual函数的class是abstract class. 不能创建abstract class的实体. 2.pure virtual 函数 他们必 ...
随机推荐
- luogu P2680 运输计划 65分做法
临近\(noip,AK\)不太现实,暴力才是王道,大佬无视 这里只介绍\(65\)分做法 ① \(m==1\) 的情况 很明显 就一条路径,当然要贪心选着一条路径路上的最大的边喽 傻逼分\(get 2 ...
- 啤酒和饮料|2014年蓝桥杯B组题解析第一题-fishers
啤酒和饮料|2014年第五届蓝桥杯B组题解析第一题-fishers 啤酒和饮料 啤酒每罐2.3元,饮料每罐1.9元.小明买了若干啤酒和饮料,一共花了82.3元. 我们还知道他买的啤酒比饮料的数量少,请 ...
- MySQL数据库调优技巧
原文链接:https://m.aliyun.com/bbs/read/300762.html MySQL是一个功能强大的开源数据库.随着越来越多的数据库驱动的应用程序,人们一直在推动MySQL发展到它 ...
- Java 集合、Iterator迭代器、泛型等
01集合使用的回顾 A:集合使用的回顾 a.ArrayList集合存储5个int类型元素 public static void main(String[] args) { ArrayList<I ...
- TypeScript基础学习
什么是TypeScript? TypeScript是一种由微软开发的自由的和开源的编程语言,它是JavaScript的一个超集,扩展了JavaScript的语法. TypeScript支持任意浏览器, ...
- mysql创建utf8数据库
1.创建 CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 2.修改 ALTER DATABASE ...
- django用包来组织模型
在我们使用python manage.py startapp xxx命令创建新的应用时,Django会自动帮我们建立一个应用的基本文件组织结构,其中就包括一个models.py文件.通常,我们把当前应 ...
- [原]设置vs的release版本调试
通过三步设置就可以实现realse下的调试啦: 1.设置“C/C++”------>“常规”------->“调试信息格式”设置成:“程序数据库(/Zi)” 2.设置“链接器”------ ...
- 使用innerHTML时要注意的一点
为某个元素添加内容时,使用的是document.getElementsByClassName,由于只有一个元素拥有这样的ClassName,就直接这样用,document.getElementsByC ...
- 关于怎么解决java.lang.NoClassDefFoundError错误
五一在部署新的统一登录时,遇到这样一个问题: 很容易把java.lang.NoClassDefFoundError和java.lang.ClassNotfoundException这两个错误搞混,事实 ...