前言

前面讲了封装,但封装只是隐藏了类内部实现。如果使用多态隐藏类本身的话,只有封装是不够的,还需要继承。

继承

通过封装。我们把一些相关的函数和变量包裹在了一起,这些函数和变量就叫做类的成员函数成员变量。继承就是一种获取这个类的成员函数和成员变量的方式。通常,继承了某个类的类叫做该类的派生类或者子类。

根据封装的意义,当父类将部分成员函数和成员变量的访问权限设置为private时,即使被继承了,子类仍然无法访问。

下面通过例子来说明一下,子类是如何保存这些继承来的成员函数和成员变量的。

class A
{
public:
    A() : a( 1 )
    {
    }
    void foo()
    {
        std::cout << "A::foo()"  << std::endl;
        return;
    }
private:
    int a;
};
class B : public A
{
public:
    B() : b( 2 )
    {
    }
private:
    int b;
};
int main()
{
    B x;
    x.foo();
    return 0;
}

继承可以是public、protected或private,不同关键字为父类设置了不同访问权限。

  • public继承意味着父类所有成员成员变量的访问权限在子类中维持不变
  • protected继承意味着父类中public的成员函数和成员变量在子类中变为protected
  • private继承意味着父类中public和protected的成员函数和成员变量在子类中变为private

成员函数

因为类成员函数可以通过隐式参数this区分具体的调用对象,所以类成员函数只需要存在一份就可以。当子类继承父类的成员函数时,子类只是得到了通过子类对象访问父类成员函数的权利。

隐式参数意味着你没有写,但是编译器帮你写了。

当我们gdb调试上面的代码时,会发现x.foo()实际调用的就是A::foo(),而不是A::foo()的一份拷贝。

   0x00000000004004fe <+8>:     lea    -0x10(%rbp),%rax   # -0x10(%rbp)就是x的地址
   0x0000000000400502 <+12>:    mov    %rax,%rdi # 将x的地址作为A::foo()的参数,也就是this
   0x0000000000400505 <+15>:    callq  0x400512 <A::foo()>

其实任何函数都只需要存在一份,成员函数只是一个稍微特殊的函数。

虚函数又是一个稍微特殊的成员函数,它也只存在一份,只不过是在调用上可能要多些操作,细节在讲多态的时候再说。

成员变量

每个类的实例对象都要变更自己的成员变量,因此其空间肯定都是独立的。当子类继承父类的成员变量时,实际只是继承了父类的数据结构。
当通过gdb打印x的值时,我们会发现它的结构如下

(gdb) p x
$1 = {<A> = {a = 1}, b = 2}

当我们直接查看x的地址的内容时,会发现A::aB::b就是连续排布的。

(gdb) x /2x &x
0x7fffffffe540: 0x00000001  0x00000002

也就是说当子类继承父类时,子类的数据结构就是父类的成员变量加上子类自身的成员变量。

之所以父类的成员变量放在前,是因为父类指针可以直接指向子类,当以父类指针操作父类成员变量时就不需要额外进行地址偏移了。如果子类成员变量在前,那么父类指针操作时还需要跳过子类成员变量。

我们大胆推测当子类继承多个父类时,子类的数据结构就是写在前的父类的成员变量加上写在后的父类的成员变量再加上子类自身的成员变量,事实也确实如此。

多继承时,因为存在多个父类数据结构,所以当不同的父类指针指向子类时,会进行一定偏移,保证该父类指针刚好指向自己的数据结构的起始位置。
多继承会复杂化类关系图,而且在一些场景下会带来歧义,因此都不建议使用多继承。反正我自己到现在为止都没在实际项目中用过,只是在一些开源代码中看到过。

结语

继承除了是多态的基础外,还是一种复用代码的方式。但是谨记只有存在父子关系时才使用继承,如果只是为了复用代码的话,应当使用组合。

C++系列总结——继承的更多相关文章

  1. C++ 系列:继承

    Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...

  2. Python基础系列讲解——继承派生和组合的概念剖析

    Python作为一门面向对象的语言,它的面向对象体系中主要存在这么两种关系,一个是“类”和“实例”的关系,另一个是“父类”和“子类”的关系. 所谓“类”是从一堆对象中以抽象的方式把相同的特征归类得到的 ...

  3. Java入门系列之类继承、抽象类、接口(五)

    前言 C#和Java关于类.抽象类.接口使用方式基本相似,只是对应关键字使用不同罢了,本节呢,我们只是对照C#和Java中关于这三个概念在具体使用时,看看有哪些不一样的地方. 类继承 C#和Java在 ...

  4. Java基础系列 - 抽象类继承和接口实现

    package com.inter; /** * 继承和接口的关系,单继承,多接口 * java不支持多继承,但可通过接口实现多重继承 */ public class test2 { public s ...

  5. Java基础系列 - 子类继承父类,调用父类的构造函数

    package com.test7; public class test7 { public static void main(String[] args) { Son son = new Son(1 ...

  6. JavaScript总结3—对象

    对象是JavaScript的基本类型,他可以从一个称为原型的对象继承属性,这种原型式继承是JavaScript的核心特征.对对象比较常见的操作有:创建,设置,查找,删除,检测和枚举他的属性.每个对象都 ...

  7. 简学Python第二章__巧学数据结构文件操作

    #cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...

  8. 从零开始学 Web 之 CSS(二)文本、标签、特性

    大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...

  9. Css学习(2)

    1 标签分类(显示方式) 块元素 典型代表,Div,h1-h6,p,ul,li 特点: ★独占一行 ★可以设置宽高 ★ 嵌套(包含)下,子块元素宽度(没有定义情况下)和父块元素宽度默认一致. 行内元素 ...

随机推荐

  1. 哎呀,我老大写Bug啦——记一次MessageQueue的优化

    MessageQueue,顾名思义消息队列,在系统开发中也是用的比较多的一个中间件吧.我们这里主要用它来做日志管理和订单管理的,记得老老大(恩,是的,就是老老大,因为他已经跳槽了)还在的时候,当时也是 ...

  2. 深入理解java虚拟机之java内存区域

    java虚拟机在执行java程序的时候会把它所管理的内存分为多个不同的区域,每个区域都有不同的作用,以及由各自的生命周期,有些随着虚拟机进行的启动而存在,有些区域则依赖于用户线程的启动或结束而建立或销 ...

  3. DDD「领域驱动设计」分层架构初探

    前言 基于 DDD 传统分层架构实现. 项目 github地址:https://github.com/WuMortal/DDDSample 这个分层架构是工作中项目正在使用的分层架构,使用了一段时间发 ...

  4. 怎么动态生成js变量

    动态生成全局变量: //简单的用字符串作为变量名 window['hello'] = "hello, world"; alert(hello);   //批量定义 for(var  ...

  5. MySQL 数据库字符集 utf8 和 utf8mb4 的区别

    参考于今日头条上Java芋道源码的-----记住:永远不要在 MySQL 中使用 UTF-8 字符集选择 MySQL 的 utf8 实际上不是真正的 UTF-8.utf8 只支持每个字符最多三个字节, ...

  6. 5G+边缘计算,着眼可见的未来

    在 2019 年 2 月巴塞罗那举办的 MWC(世界移动通讯大会)上,华为手机带来了一款超薄的 5G 折叠屏手机 Mate X.这款手机将折叠屏和 5G 结合在一起,引起了不少人的关注与舆论,而昂贵的 ...

  7. CSharpGL(46)用Billboard绘制头顶文字

    CSharpGL(46)用Billboard绘制头顶文字 本文介绍CSharpGL用Billboard绘制头顶文字的方法.效果如下图所示. 下载 CSharpGL已在GitHub开源,欢迎对OpenG ...

  8. c#根据路径(url)下载图片

    方法一:根据路径下载图片 1 /// <summary> /// 图片另存为 /// </summary> /// <param name="url" ...

  9. Android studio无法创建类和接口问题解决办法。提示 Unable to parse template "Class"

    重新配置了studio 的工作环境, 没问题,后来加需求要新增java类和接口,这就出现问题了,新建的时候,就会报错: Unable to parse template "Interface ...

  10. 关于IT公司技术委员会职责

    技术委员会的核心职责 组织人才相关 • 制定职级标准 - 能力框架:知识,技能,通用素质 - 职级标准:T2T3T4-P7P8P9- • 职级评审,对齐标准 • 高端招聘,对齐标准 • 校园招聘,对齐 ...