• C++基础知识:继承


    1.继承的概念

    面向对象中的继承指类之间的父子关系
    子类拥有父类的所有成员变量和成员函数
    子类就是一种特殊的父类
    子类对象可以当作父类对象使用
    子类可以拥有父类没有的方法和属性

    2.C++中的访问级别与继承
    public继承
      父类成员在子类中保持原有访问级别
    private继承
      父类成员在子类中变为private成员

    注意:
    C++中class的继承默认为private继承
    private继承的子类拥有父类的所有成员
    private继承使得父类的所有成员在子类中变为private成员

     3.类的protected成员
    protected成员可以在子类中被访问,但不能在外界被访问
    protected成员的访问权限介于public和private之间

    4.类成员访问级别设置的原则
    需要被外界访问的成员直接设置为public
    只能在当前类中访问的成员设置为private
    只能在当前类和子类中访问的成员设置为protected
    private成员在子类中依然存在,但是却无法访问到!

    5.继承中的构造与析构

    ①赋值兼容性原则

    子类对象可以当作父类对象使用
    子类对象可以直接赋值给父类对象
    子类对象可以直接初始化父类对象
    父类指针可以直接指向子类对象
    父类引用可以直接引用子类对象

    子类是就是特殊的父类

    ②类在C++编译器的内部可以理解为结构体,子类是由父类成员叠加子类新成员得到的:

    ③在子类对象构造的时候需要调用父类构造函数对其继承得来的成员进行初始化:

     ④在子类对象析构的时候需要调用父类析构函数对其继承得来的成员进行清理

    子类对象在创建时会首先调用父类的构造函数
    父类构造函数执行结束后,执行子类的构造函数
    当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
    析构函数调用的先后顺序与构造函数相反

    ⑤继承与组合的混搭:

    如果一个类继承自父类并且有其它的对象作为成员,那么构造函数如何调用?

    口诀:先父母,后客人,再自己。

    ⑥当子类成员变量与父类成员变量同名时:
    子类依然从父类继承同名成员
    在子类中通过作用域分别符::进行同名成员区分
    同名成员存储在内存中的不同位置

     6.继承与多态

    ①函数重写:

    在子类中定义与父类中原型相同的函数
    函数重写只发生在父类与子类之间
    父类中被重写的函数依然会继承给子类
    默认情况下子类中重写的函数将隐藏父类中的函数
    通过作用域分辨符::可以访问到父类中被隐藏的函数

    ②当函数重写遇上赋值兼容性原则

    问题所在:
    C++与C相同,是静态编译型语言
    在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象
    所以编译器认为父类指针指向的是父类对象(根据赋值兼容性原则,这个假设合理)
    由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象
    从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数

    在编译这个函数的时候,编译器不可能知道指针 p 究竟指向了什么。

    但是编译器没有理由报错。于是,编译器认为最安全的做法是编译到父类的print函数,因为父类和子类肯定都有相同的print函数。

    ③多态应用:C++支持两种多态性:编译时多态性,运行时多态性。
      a.编译时多态性: 通过函数重载和运算符重载来实现的。  
      b 运行时多态性:通过继承和虚函数来实现的。

    根据实际的对象类型来判断重写函数的调用
    如果父类指针指向的是父类对象则调用父类中定义的函数
    如果父类指针指向的是子类对象则调用子类中定义的重写函数

    C++中的多态支持:
      C++中通过virtual关键字对多态进行支持(传说中的虚函数)
      使用virtual声明的函数被重写后即可展现多态特性

    C++中多态的实现原理
      当类中声明虚函数时,编译器会在类中生成一个虚函数表
      虚函数表是一个存储类成员函数指针的数据结构
      虚函数表是由编译器自动生成与维护的
      virtual成员函数会被编译器放入虚函数表中
      存在虚函数时,每个对象中都有一个指向虚函数表的指针

    虚函数的深入理解:

    通过虚函数表指针VPTR调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确定真正应该调用的函数。

    而普通成员函数是在编译时就确定了调用的函数。在效率上,虚函数的效率要低很多。

    对象中的VPTR指针什么时候被初始化?

      对象在创建的时候由编译器对VPTR指针进行初始化
      只有当对象的构造完全结束后VPTR的指向才最终确定
      父类对象的VPTR指向父类虚函数表
      子类对象的VPTR指向子类虚函数表

    结论:构造函数中调用虚函数无法实现多态。
       

    虚函数:在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载

    纯虚函数:纯虚函数是只声明函数原型,而故意不定义函数体的虚函数。

    面向对象中的抽象类:抽象类可用于表示现实世界中的抽象概念,包含纯虚函数的类称为抽象类
              抽象类是一种只能定义类型,而不能产生对象的类
              抽象类只能被继承并重写相关函数
              抽象类的直接特征是纯虚函数
              抽象类不能用于定义对象
              抽象类只能用于定义指针和引用
              抽象中的纯虚函数必须被子类重写

    ④函数的重载/重写

  • 相关阅读:
    4种常见的缓存问题及解决方案详解
    如果你不了解Java的JVM,那真的很难进BAT一线大厂!
    终于有人把分布式事务说清楚了!
    这3个并发编程的核心,你一定要知道!
    Java垃圾回收机制你还不明白?一线大厂面试必问的!
    几种置换算法
    [ERR] Node 172.168.63.202:7001 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or contains some
    redis集群添加删除节点
    redis集群安装部署
    在Ubuntu下永久修改主机名
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/6478485.html
Copyright © 2020-2023  润新知