很多人认为,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++中的接口继承和实现继承的更多相关文章

  1. 第五节:详细讲解Java中的接口与继承

    前言 大家好,给大家带来详细讲解Java中的接口与继承的概述,希望你们喜欢 什么是接口(interface) 接口中的方法都是抽象方法,public权限,全是抽象函数,不能生成对象 interface ...

  2. 【Java面试题】60 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法?

    接口可以继承接口.抽象类可以实现(implements)接口,抽象类可以继承具体类.抽象类中可以有静态的main方法. 问:  抽象类是否可继承实体类 (concrete class) 答: 抽象类是 ...

  3. Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现

    前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...

  4. Java中的集合(六)继承Collection的Set接口

    Java中的集合(六)继承Collection的Set接口 一.Set接口的简介 Set接口和List接口都是继承自Collection接口,它与Collection接口中功能基本一致,并没有对Col ...

  5. Java中的集合(五)继承Collection的List接口

    Java中的集合(五)继承Collection的List接口 一.List接口简介 List是有序的Collection的,此接口能够精确的控制每个元素插入的位置.用户能够根据索引(元素在List接口 ...

  6. Java中的集合(三)继承Collection的Queue接口

    Java中的集合(三)继承Collection的Queue接口 一.Queue介绍 Queue接口继承自Collection接口,是Java中定义的一种队列数据结构,元素是有序的(按插入顺序排序),先 ...

  7. Effective C++ 34 区分接口继承和实现继承

    public继承从根本上讲,有两部分:接口继承和实现继承.两者之前的区别很像函数声明与函数定义. 具体设计中,会呈现三种形式:derived class只继承成员函数的接口(纯虚函数):derived ...

  8. c++ 接口继承和实现继承

    所谓接口继承,就是派生类只继承函数的接口,也就是声明:而实现继承,就是派生类同时继承函数的接口和实现. 我们都很清楚C++中有几个基本的概念,虚函数.纯虚函数.非虚函数. 虚函数: 虚函数是指一个类中 ...

  9. JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)

    实现线程并发有两种方式:1)继承Thread类:2)实现Runnable接口. 线程基础 1)程序.进程.线程:并行.并发. 2)线程生命周期:创建状态(new一个线程对象).就绪状态(调用该对象的s ...

  10. pure virtual、impure virtual、non-virtual函数的接口继承和实现继承

    1.abstract class 拥有pure virtual函数的class是abstract class. 不能创建abstract class的实体. 2.pure virtual 函数 他们必 ...

随机推荐

  1. SpringBoot中的Quartz应用

    Spring自带定时器任务: code: import org.springframework.beans.factory.annotation.Configurable; import org.sp ...

  2. 蚂蚁感冒|2014年蓝桥杯B组题解析第八题-fishers

    蚂蚁感冒 长100厘米的细长直杆子上有n只蚂蚁.它们的头有的朝左,有的朝右. 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒. 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行. 这些蚂蚁中,有1只蚂 ...

  3. firefox、chrome的DNS缓存清除方法

    通过设置hosts文件可以强制指定域名对应的IP,当修改hosts文件,想要浏览器生效,最直接的方法关闭浏览器后重新开启:如果不想重启浏览器,只需要清空浏览器的DNS缓存即可. 清空DNS缓存在chr ...

  4. redis.conf 配置 详解 中文 2.8

        # redis version 2.8.19   # 1k => 1000 bytes# 1kb => 1024 bytes# 1m => 1000000 bytes# 1m ...

  5. 51nod 1051 最大子矩阵和

    没想到居然可以O(n3)暴力过 就是大概之前的  最大连续子序列和 加成2维度了  枚举起始列 和 终止列 然后计算从1到n行最大的子矩阵的和 注意n 和 m 的输入顺序!! #include< ...

  6. LA 4080 战争和物流(最短路树)

    https://vjudge.net/problem/UVALive-4080 题意:给出一个n个结点m条边的无向图,每条边上有一个正权.令c等于每对结点的最短路长度之和.不连通的两点的最短路长度视为 ...

  7. codeforces 251 div2 C. Devu and Partitioning of the Array 模拟

    C. Devu and Partitioning of the Array time limit per test 1 second memory limit per test 256 megabyt ...

  8. Ubuntu 14.04 编写service 服务

    有时我们需要将特定操作封装成服务,通过服务启动停止,例如nginx的启动停止,service nginx start 或者service nginx stop 下面我们将编写一个demo cd /et ...

  9. shell 使用变量

    使用变量 使用一个定义过的变量,只要在变量名前面加美元符号即可,如: your_name="qinjx" echo $your_name echo ${your_name} 变量名 ...

  10. VS 常见快捷键有哪些

    自动对齐点[编辑]-[高级]-[设置选定内容的格式]或者按Ctrl + K 然后再按Ctrl + F 就好了 你可以在常用快捷键自定义 窗口中进行查看1.进入工具-选项 对话框2.选择[环境]-[键盘 ...