当前位置: 首页 > news >正文

C++特性之一:继承

1. 派生类的成员变量、成员函数、构造、析构

在这里插入图片描述

2. 继承的切片

在这里插入图片描述

3. 重定义/隐藏

重定义/隐藏:派生类和基类有同名的成员,就叫隐藏。派生类的成员隐藏了基类的成员。

隐藏时可以通过类作用限定符来访问被隐藏的成员。

class Person
{
public:void Print(){cout << "Person " << ID << endl;}string name;	// 姓名int ID = 0;			// 身份证号
};// 派生类Student继承了基类Person
class Student : public Person
{
public:void Print(){cout << "Student " << ID << endl;}int ID = 1;	// 学号
};// 派生类Teacher继承了基类Student
class Teacher : public Student
{
public:void Print(){cout << "Teacher " << ID << endl;}int ID = 2;	// 工号
};
// 重定义/隐藏
void Test3()
{// 在上面的三个类中,成员函数Print()和成员变量ID都属于隐藏/重定义Person per;Student stu;Teacher tea;tea.Print();tea.Student::Print();tea.Person::Print();
}
// 输出结果为:
// Teacher 2
// Student 1
// Person 0

4. 派生类的默认成员函数

在说继承的切片时提到,我们可以将派生类中从基类那里拷贝过来的一部分成员变量看作一个整体,视为一个新的成员变量,它的类型是基类。
因此,在讨论派生类的默认成员函数的时候,我们就能明白一些规则。

为了方便叙述,我们对派生类进行以下划分:
在这里插入图片描述

  1. 构造函数

    在类中,若存在一个成员变量也是一个类,那么构造函数就会自动调用这个成员变量的默认构造函数,这里也是这个道理。

    派生类的构造函数会调用基类的默认构造函数,以完成对属于基类的那一部分的成员(上图的A部分)的初始化。如果基类没有默认构造函数,那么在派生类的构造函数中,就要显式调用基类的构造函数。

    先调用基类的构造,完成对A部分的构造,再构造B部分自己。

  2. 拷贝构造

    B部分的拷贝需要派生类自己来实现,但是A部分,则需要调用基类的拷贝构造函数来完成拷贝。

  3. 赋值运算符重载 operator=

    同理,A部分也需要调用基类的赋值运算符重载来完成这部分的赋值初始化。

  4. 析构函数

    先完成对B部分的析构,然后不用显式调用,编译器会自动调用基类的析构函数,来完成A部分的析构。

5. 继承与友元

友元关系并不能继承。
基类的友元,并不是派生类的友元,就好比父亲的朋友并不一定是孩子的朋友。
如果想要既是基类的友元,又是派生类的友元,则需要在两个类中都声明友元。

6. 继承与静态成员

基类中的静态成员,会和成员函数一样,仅仅生成一份,所有派生类用到的静态成员,都是这一份。这样做避免空间浪费。

7. 菱形继承和菱形虚拟继承

C++中允许多继承,也就是一个类继承了两个父类,这必然导致一个问题:菱形继承,请参考下图:
在这里插入图片描述

可见,在D类对象中,存了两份int a,这导致二义性和数据冗余的问题,在访问d对象中的a成员时,访问的是从B类中继承来的a呢,还是从C类中继承来的a?当然,解决方案就是:继承时,在作用域限定符::后加上关键字virtual
这便是虚拟继承,可以让int a 进存一份,B类对象、C类对象以及D类对象,仅需通过偏移量就可以得到a的地址。

用域限定符::后加上关键字virtual
这便是虚拟继承,可以让int a 进存一份,B类对象、C类对象以及D类对象,仅需通过偏移量就可以得到a的地址。

8. 组合

相关文章:

  • C++中PostMessage和SendMessage函数的用途、区别、使用方法及使用示例
  • IDEA启动项目到一半后卡住但不报错的解决方法分享
  • [MYSQL数据库]- 索引
  • ElasticSearch深度分页问题如何解决
  • 数据结构:图的存储与遍历(待续)
  • 同态滤波算法详解
  • Docker进阶:深入了解 Dockerfile
  • 采购代购系统独立站,接口采集商品上货
  • L1-039 古风排版(C++)
  • 基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的条形码二维码检测系统(深度学习+UI界面+训练数据集+Python代码)
  • Oracle 死锁、指标汇总
  • 有点NB的免费wordpress主题模板
  • Neo4j 批量导入数据 从官方文档学习LOAD CSV 命令 小白可食用版
  • PHP+Lunix+GIT 如何快速使用宝塔WebHook快速自动化部署
  • C++训练营:引用传递
  • 30天自制操作系统-2
  • DOM的那些事
  • Javascript编码规范
  • JavaWeb(学习笔记二)
  • java中具有继承关系的类及其对象初始化顺序
  • Python中eval与exec的使用及区别
  • Vue实战(四)登录/注册页的实现
  • vue数据传递--我有特殊的实现技巧
  • 成为一名优秀的Developer的书单
  • 构建工具 - 收藏集 - 掘金
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 基于webpack 的 vue 多页架构
  • 学习ES6 变量的解构赋值
  • 移动端解决方案学习记录
  • 从如何停掉 Promise 链说起
  • 浅谈sql中的in与not in,exists与not exists的区别
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​【已解决】npm install​卡主不动的情况
  • #07【面试问题整理】嵌入式软件工程师
  • #Z0458. 树的中心2
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (ibm)Java 语言的 XPath API
  • (pytorch进阶之路)扩散概率模型
  • (Ruby)Ubuntu12.04安装Rails环境
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (五)c52学习之旅-静态数码管
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • .Net MVC + EF搭建学生管理系统
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET中的Exception处理(C#)
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • @Import注解详解
  • @Pointcut 使用
  • [52PJ] Java面向对象笔记(转自52 1510988116)
  • [AIGC codze] Kafka 的 rebalance 机制
  • [android学习笔记]学习jni编程