1.接口继承与实现继承的区别

《Effective C++》条款三十四:区分接口继承和实现继承中介绍的比较啰嗦,概括地说需要理解三点:

(1)纯虚函数只提供接口继承,但可以被实现;

(2)虚函数既提供接口继承,也提供了一份默认实现,即也提供实现继承;

(3)普通函数既提供接口继承,也提供实现继承。

这里假定讨论的成员函数都是public的。

这里回顾一下这三类函数,如下:

class BaseClass
{
public:
     void virtual PureVirtualFunction() = 0; // 纯虚函数
     void virtual ImpureVirtualFunction(); // 虚函数
     void CommonFunciton(); // 普通函数
 }; 

纯虚函数有一个“等于0”的声明,具体实现一般放在派生中(但基类也可以有具体实现),所在的类(称之为虚基类)是不能定义对象的,派生类中仍然也可以不实现这个纯虚函数,交由派生类的派生类实现,总之直到有一个派生类将之实现,才可以由这个派生类定义出它的对象。

虚函数必须有实现,否则会报链接错误。虚函数可以在基类和多个派生类中提供不同的版本,利用多态性质,在程序运行时动态决定执行哪一个版本的虚函数(机制是编译器生成的虚表)。virtual关键字在基类中必须显式指明,在派生类中不必指明,即使不写,也会被编译器认可为virtual函数,virtual函数存在的类可以定义实例对象。

普通函数则是将接口与实现都继承下来了,如果在派生类中重定义普通函数,将同名函数隐藏。事实上,也是极不推荐在派生类中隐藏基类的普通函数,如果真的要这样做,请一定要考虑是否该把基类的这个函数声明为虚函数或者纯虚函数。

下面看一个示例程序。

CShape是一个几何图形的基类,对于任何一个几何图形来说,绘制和设置颜色都是合理的操作,因此可以按照如下方式设计类:

class CShape{
public:
    virtual void draw()=0;
    virtual void setColor(const Color& color);
private:
    Color m_color;
};

class CCircle:public CShape{};
class CEllipse:public CShape{};

上面几个类的申明就可以很好的展示继承的两个相互独立的部分:函数接口继承(inheritance of function interfaces)和函数实现继承(inheritance of function implementations)。

在基类CShape中,不能够为每一种不同的图形提供一个默认的draw实现,所以设置为纯虚函数,留给派生类来实现,也就说派生类只是继承了一个借口而已。圆和椭圆有着自己的绘制方式,所以各自有独自的绘制实现。

对于CShape::setColor,将其设置为普通的虚函数,提供一个默认的实现,这样圆和椭圆既可以重新定义,也可以使用基类的默认实现。使用普通的虚函数,派生类既使用了接口继承,也使用了实现继承。

2.接口继承与实现继承的选择

类设计时,接口继承与实现继承相互独立,代表着一定的设计意义,在二者之间进行选择时,我们需要考虑一个因素:对于无法提供默认版本的函数接口选择函数接口继承,对于能够提供默认版本的函数接口,选择函数实现继承。


参考文献

[1]读书笔记Effective_C++条款三十四:区分接口继承和实现继承

[2]李健.编写高质量代码:改善C++程序的150个建议[M].第一版.北京:机械工业出版社,2012.1:314-315

C++接口继承与实现继承的区别和选择的更多相关文章

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

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

  2. Effective C++:规定34:区分接口继承和实现继承

    (一个) class Shape { public: virtual void draw() const = 0; virtual void error(const string& msg); ...

  3. 7 -- Spring的基本用法 -- 8... 抽象Bean与子Bean;Bean继承与Java继承的区别;容器中的工厂Bean;获得Bean本身的id;强制初始化Bean

    7.8 深入理解容器中的Bean 7.8.1 抽象Bean与子Bean 把多个<bean.../>配置中相同的信息提取出来,集中成配置模版------这个配置模版并不是真正的Bean,因此 ...

  4. java一个类 继承HttpServlet 和实现Servlet区别

    java一个类 继承HttpServlet 和实现Servlet区别 servlet 是一个接口,如果实现这个接口,那么就必须实现接口里面定义的所有方法 而HttpServlet实现了servlet接 ...

  5. Effective C++ -----条款34:区分接口继承和实现继承

    接口继承和实现继承不同.在public继承之下,derived classes总是继承base class的接口. pure virtual函数只具体指定接口继承. 简朴的(非纯)impure vir ...

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

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

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

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

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

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

  9. [Java] 类和接口的初始化步骤 - 继承方面

    类和接口在初始化化时,处理继承层级的方法不一样. 类继承的初始化:通过引用 static 字段,触发某个类的初始化,则声明该字段的类,以及该类的父类被初始化. 接口继承的初始化:通过引用 static ...

随机推荐

  1. jar包冲突常用的解决方法

    jar包冲突常见的异常为找不到类(java.lang.ClassNotFoundException).找不到具体方法(java.lang.NoSuchMethodError).字段错误( java.l ...

  2. 【Docker】第二篇 Docker镜像管理

    一.搜索镜像 1.下载一个docker镜像:我们可以通过登陆docker网站搜索自己需要的镜像,可以选择自己所需要的版本,然后通过详情也可以看到:网址:https://hub.docker.com/2 ...

  3. 使用NNI的scikit-learn以及Tensorflow分析

    一.NNI简介 NNI (Neural Network Intelligence) 是自动机器学习(AutoML)的工具包. 它通过多种调优的算法来搜索最好的神经网络结构和(或)超参,并支持单机.本地 ...

  4. PHP中的__toString() 是什么东西

    __toString()  是魔术方法的一种,具体用途是当一个对象被当作字符串对待的时候,会触发这个魔术方法 以下说明摘自PHP官方手册 public string __toString ( void ...

  5. Ajax中post后台.net MVC中Controller的路径问题。

    今天使用ajax的post方法,去访问mvc的controller,url的传值是 "//ProductCatalog/PostShareInfo",发现无论如何都访问不到. 我实 ...

  6. 第三个spirit(第十四天)

    一 .进度(自习室) 本来十号要开始进行第三次冲刺,不过因为团队很多成员要进行协会和组织的换届,而且团队还换了新 人又加了人进来,所以我们今天才是第三次冲刺的第一天.我们进行了新团队的第一次会议.基于 ...

  7. 《简明Python教程》学习笔记

    <简明Python教程>是网上比较好的一个Python入门级教程,尽管版本比较老旧,但是其中的基本讲解还是很有实力的. Ch2–安装Python:下载安装完成后,在系统的环境变量里,在Pa ...

  8. Appium 服务关键字(转)

    来源: https://github.com/appium/appium/blob/master/docs/cn/writing-running-appium/caps.cn.md#appium-服务 ...

  9. oracle 3大范式 理解

    CREATE OR REPLACE PACKAGE pack3 AS FUNCTION fun_calc (num1 NUMBER ,num2 NUMBER ) RETURN number ; fun ...

  10. 用go实现的一个堆得数据结构

    用golang实现的堆,主要提供了两个方法,push和pop及堆的大小,代码如下: package main import ( "errors" "fmt" ) ...