c++: 继承的详解(理解)

目录

 

继承的相关概念:

继承权限&访问限定符

赋值兼容规则(public继承)

继承中的作用域:

派生类的默认成员函数:

【面试题】

继承与友元:

继承与static静态成员:

继承体系下派生类的对象模型:


继承的相关概念:

复用:重复性的代码肯定是越少越好,随着组织越来越复杂,单纯在main()中写代码会变的越来越难以维护。而函数则更像是一个小的程序。

          可以从主函数中脱离出来,使我们可以将任务划分的跟更小,大大降低了我们的程序整体复杂性,函数让我们实现了一定程度的代码复用。

继承:继承的机制是面向对象程序设计使代码可以复用的一种手段,它允许程序员在保持原有类特性的基础上继承扩展,增加功能。这样产生的类

          成为派生类!

继承的格式:

继承权限&访问限定符

三种类成员访问限定符:

  1. public公有
  2. protected保护
  3. private私有

三种继承关系

  1. public公有继承
  2. protected保护继承
  3. private私有继承

继承方式及继承权限对应表:

总结:

  1. 基类private成员在派生类中不可访问(如果基类成员不想在类外被直接访问,但需要在派生类中访问就定义为protected,保护成员限定符因继承才出现
  2. public继承是一个接口继承,保持is-a的原则,每个父类可用成员对子类也可用,因为每个子类对象也都是一个父类对象
  3. protected/private是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是has-a原则
  4. 不管是那种继承方式,派生类内部都可以访问基类的公有和保护成员,私有成员则不可见(编译器语法检测无法通过,所以不能访问)
  5. class默认private,struct默认public
  6. 一般使用public,极少场景才会使用其他

赋值兼容规则(public继承)

  1. 子类对象可以赋值给父类对象(切割或切片:仅把父类含有的对象进行赋值)
  2. 父类对象不能赋值给子类对象
  3. 父类的指针或引用可以指向子类对象
  4. 子类的指针或引用不能指向父类对象(可以通过强制类型转换完成,但是不能调用成员函数,会崩溃)

继承中的作用域:

  1. 在继承体系中基类和派生类都有独立的作用域
  2. 子类和父类中有同名成员,子类将屏蔽对同名成员的直接访问(在子类成员中:可以使用基类::基类成员 访问)--(隐藏或重定义)
  3. 在实际体系中最好不要定义同名成员

派生类的默认成员函数:

派生类如果没有显示定义这六个默认成员函数,编译器则会合成

合成:必须依赖与基类,根据基类的相应成员的行为来合成派生类的默认成员函数

生成:不依赖于任何东西,只是编译器根据类的定义简单生成基于基础类型的成员函数

  1. 基类没有缺省构造函数,派生类必须要在初始化类表中显式给出基类名和参数列表
  2. 基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数
  3. 基类定义了带有形参表构造函数,派生类就一定定义构造函数

【面试题】

系统自动调用析构原因:保证先析构子类在析构父类(子类隐藏了父类的析构函数)栈结构规则

                                     同理:子类初始化时调用父类的默认成员函数初始化父类,调用自己的默认成员函数初始化自己

栈结构:先初始化父类在子类,先析构子类在析构父类

实现一个不能被继承的类:将父类的构造函数定义成私有!

                                       子类合成时先调用父类构造函数,因为私有所有失败!

继承与友元:

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员(父亲的朋友,不一定是孩子的朋友)

继承与static静态成员:

基类定义了static静态成员,则整个继承体系中只有一个这样的成员,无论派生出多少子类都只有static

继承体系下派生类的对象模型:

                对象模型为对象中非静态成员变量在内存中的布局形式,与成员函数无关

  1. 单继承:一个子类只有一个直接父类
  2. 多继承:一个子类有两个或以上直接父类 
  3.       菱形继承                  我们发现Assistant类中存在两份Person对象,因此在访问继承于基类的成
    员变量时,会存在数据冗余及二义性的问题                                                                                                                                二义性:两边都有(选择困难) 解决方式:1》指定访问那个父类2》虚继承
  4. 虚拟继承——  解决菱形继承的二义性和数据冗余的问题

虚拟继承在进程权限前面加上virtual关键字即可构成虚拟继承

特点:在任何派生类中的virtual基类总共用同一个(共享)对象表示

【注意】:尽量不要设计菱形继承的类
虚继承和直接继承有什么区别
1.时间:在通过继承类对象访问虚基类对象中的成员(包括数据成员和函数成员)时,都必须通过某种间接引用来
完成,这样会增加引用寻址时间(就和虚函数一样),其实就是调整this指针以指向虚基类对象,只不过这个调整
是运行时间接完成的。
2.空间:由于共享所以不必要在对象内存中保存多份虚基类子对象的拷贝,这样较之 多继承节省空间。虚拟继承与
普通继承不同的是,虚拟继承可以防止出现菱形继承时,一个派生类中同时出现了两个基类的子对象。也就是说,
为了保证 这一点,在虚拟继承情况下,基类子对象的布局是不同于普通继承的。因此,它需要多出一个指向基类子
对象的指针

猜你喜欢

转载自blog.csdn.net/W_J_F_/article/details/82844049
今日推荐