• C++ —— 继承


    目录

    继承的概念及定义

    继承关系和访问限定符

    继承基类成员访问方式的变化

    总结

    基类和派生类对象赋值转换

    继承中的作用域

    派生类的默认成员函数

    如何设置一个不能继承的类?

    继承与友元

    继承与静态成员

    菱形继承及菱形虚拟继承

    虚拟继承解决数据冗余和二义性的原理


    C语言总结在这常见八大排序在这

    作者和朋友建立的社区:非科班转码社区-CSDN社区云💖💛💙

    期待hxd的支持哈🎉 🎉 🎉

    最后是打鸡血环节:你只管努力,剩下的交给天意🚀 🚀 🚀  

    继承的概念及定义

    继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段,它允许程序员在 保持原有类特 性的基础上进行扩展 ,增加功能,这样产生新的类,称派生类。继承 呈现了面向对象程序设计的层次结构 ,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用, 继承是类设计层次的复用

    继承关系和访问限定符

    继承基类成员访问方式的变化

    总结

    1. 基类 private 成员在派生类中无论以什么方式继承都是不可见的。这里的 不可见是指基类的私有成员还是 被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它
    2. 基类 private 成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected 可以看出保护成员限定符是因继承才出现的
    3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min( 成员在基类的访问限定符,继承方式 ) public > protected > private
    4. 使用关键字 class 时默认的继承方式是 private ,使用 struct 时默认的继承方式是 public 不过最好显示的 写出继承方式
    5. 在实际运用中一般使用都是 public 继承,几乎很少使用 protetced/private 继承 ,也不提倡使用protetced/private继承,因为 protetced/private 继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。
    PS:很好记,就是取两者中小的为最终访问权限。

    基类和派生类对象赋值转换

    派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用 。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。
    注意公有继承才可以
    不能反过来父类给子类
    但是指针可以(后面讲)
    基类对象不能赋值给派生类对象
    基类的指针可以通过强制类型转换赋值给派生类的指针。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(Run-Time Type Information) dynamic_cast 来进行识别后进行安全转换。(网图)

    继承中的作用域

    1. 在继承体系中 基类 派生类 都有 独立的作用域
    2. 子类和父类中有同名成员, 子类成员将屏蔽父类对同名成员的直接访问,这种情况叫 隐藏 ,也叫 重定义 (在子类成员函数中,可以 使用 基类 :: 基类成员 显示访问
    3. 需要注意的是如果是成员函数的隐藏, 只需要函数名相同就构成隐藏
    4. 注意在实际中在 继承体系里 面最好 不要定义同名的成员

    派生类的默认成员函数

    子类6个默认成员函数
    1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
    2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
    3. 派生类的 operator= 必须要调用基类的 operator= 完成基类的复制。
    4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序
    5. 派生类对象初始化先调用基类构造再调派生类构造。
    6. 派生类对象析构清理先调用派生类析构再调基类的析构。
    子类构造函数原则:
    a. 调用父类构造函数初始化继承自父类成员
    b. 自己再初始化自己的成员
    析构,拷贝构造,赋值重载也类似
    对于子类析构函数
    为了保证析构顺序,先子后父(栈),子类析构函数完成后会自动调用父类析构函数,所以不需要我们显示调用。
    PS:为了满足多态的需要,析构函数名统一被处理为destruct()。

    可以把父类那一坨当成一个成员去初始化
    拷贝构造示例:
    注意这里是两个切片,是还有一个this,this和s都是Student,要切片为Person
    赋值示例:

    如何设置一个不能继承的类?

    只需要把父类的构造函数private/protected
    因为这样子类构造函数的时候就无法调用父类的构造函数
    父类想要自己使用就用一个public的Creat函数去调用非public里面的构造函数返回就可以了,然后加上static,就可以不用对象去调用了哈。

    继承与友元

    友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员 

    继承与静态成员

    基类定义了 static 静态成员,则整个继承体系里面只有一个这样的成员 。无论派生出多少个子类,都只有一个static 成员实例 。
    有点传家宝的意思了。

    菱形继承及菱形虚拟继承

    单继承:一个子类只有一个直接父类时称这个继承关系为单继承

    PS:以下均为网图

     多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

    菱形继承:菱形继承是多继承的一种特殊情况

    菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在 Assistant 的对象中 Person 成员会有两份。

    虚拟继承可以解决菱形继承的二义性和数据冗余的问题。 需要注意的是,虚拟继承不要在其他地方去使用。

    虚拟继承解决数据冗余和二义性的原理

    菱形继承 

    菱形虚拟继承
    例一:

    例二:

    我们可以看出来原本应该 B C 都有的数据 A 此时放在了外面(加上virtual   a在公共区域了),而原来的对象模型发送了变化,(就是因为A没有在 B C 的2区域,所以需要去找,在自己区域里面,他有自己的方式去找,我们不用管。)多了一个续集表指针,指针的下一个位置就是 A 位置的偏移量(当前位置与多态有关,现在是预留的),然后用偏移量就可以找到 A 。prt1和ptr2无法知道也不关心自己指向的是谁!都用同样的方法去找A成员,先找到虚机表中偏移量,然后计算 A 的位置!

    PS:那static的_a会不会就解决了不用虚继承了呢?
    其实不是,static的话就是整个类共用一个
    但是如果是虚继承就是每个D对象的_a都是不一样的

    C++的缺陷:多继承,多继承很复杂,多继承会产生菱形继承情况,菱形继承会有数据冗余和二义性,数据冗余的解决就是菱形虚拟继承,菱形虚拟继承的解决就是上面那个对象模型解决

    最后的最后,创作不易,希望读者三连支持💖

    赠人玫瑰,手有余香💖

  • 相关阅读:
    C语言自定义类型:结构体
    AI大预言模型——ChatGPT与AI绘图及论文高效写作
    Linux中设置git的代理
    第十一章 JSP开发模型
    block 归纳总结 上
    MySQL 8.0 新特性之不可见主键
    【苹果相册推软件源码】iMessage提出了UDP(UserDatagramprotocol,用户数据新闻协议
    openGL通过点绘制图形
    制造企业如何优化物料控制?
    OpenFeign超时控制和日志打印功能
  • 原文地址:https://blog.csdn.net/weixin_62700590/article/details/126213183