【C++】- 继承(继承定义!!基本格式!切片概念!!菱形继承详解!)

继承

  • 了解继承
  • 继承的定义
  • 基类和派生类对象赋值转换
  • 继承中的作用域
  • 派生类的默认成员函数
  • 继承和友元
  • 菱形继承和菱形虚拟继承

了解继承

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

通俗来说,继承它允许创建基于现有类的新类。并且继承这个机制提供了一种从已有类(称为父类或基类)继承属性和方法到新类(称为子类或派生类)的方式,使得在子类中可以重用、扩展或修改基类的行为

在这里插入图片描述
在这个比喻中:

  • 祖先的绘画技巧代表了父类(基类)中定义的属性和方法。
  • 子孙继承并改进技巧代表了子类通过继承获取父类的能力,并可以添加新的属性和方法或者重写(override)父类的方法来满足新的需求。
  • 每一代人增加的自己的特色代表了面向对象编程中通过继承实现的多态性和扩展性,即同一行为(如绘画)在不同的子类中可以有不同的实现方式。

继承的定义

class Base {
public:
    void baseMethod() {}
};

class Derived : public Base {
public:
    void derivedMethod() {}
};
int main() {
    Derived d;
    d.baseMethod(); // 调用从Base类继承的方法
    d.derivedMethod(); // 调用Derived类自己的方法
    return 0;
}
这里定义了两个类:Base(基类)和Derived(派生类)。派生类Derived通过公有继承(public)的方式继承了基类Base。这意味着Derived类的对象可以访问Base类中的公有成员函数和属性,在主函数中,创建了Derived类的对象d,然后分别调用了baseMethod和derivedMethod方法。由于Derived类继承了Base类,所以d对象能够访问Base类中定义的baseMethod方法,同时也可以访问Derived类中定义的derivedMethod方法。

在上述示例中我们看到了继承可以有不同的继承方式:
在这里插入图片描述
在C++中,有三种继承方式:公有继承、私有继承和保护继承。这些继承方式定义了派生类如何继承基类的成员
在这里插入图片描述
通常情况下,公有继承是最常用和默认的继承方式,因为它能够提供最大的代码复用和功能扩展能力。私有继承和保护继承在一些特定场景下可能会有用,比如实现细节隐藏或实现接口继承。

在这里插入图片描述使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。

在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

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

在C++中,基类和派生类之间可以进行对象赋值转换,即将一个基类对象赋值给派生类对象或将一个派生类对象赋值给基类对象。不过,这种转换需要注意以下几点:

  1. 基类指针或引用可以指向派生类对象: 基类指针可以指向派生类对象的地址,这意味着通过基类指针可以访问派生类对象中继承自基类的成员。

基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类
的指针是指向派生类对象时才是安全的。

  1. 派生类指针或引用不能指向基类对象: 派生类指针或引用只能指向派生类对象,而不能指向基类对象。
  2. 派生类对象可赋值给基类对象: 将派生类对象赋值给基类对象时,只会将派生类对象中从基类继承的部分进行复制。

这里提到一个特殊的概念:切片就是指将派生类对象赋值给基类对象时,只复制了基类部分的成员,而派生类特有的成员被丢失的情况。这种操作也被称为"对象切割"。
在这里插入图片描述4. 基类对象不能赋值给派生类对象: 由于基类对象只包含基类成员,没有派生类成员,因此不能将基类对象直接赋值给派生类对象。

继承中的作用域

与定义普通的类一样,在继承体系中基类和派生类都有独立的作用域。

在继承中,派生类可以隐藏继承自基类的同名成员。当派生类定义了与基类同名的成员函数或成员变量时,派生类的成员会隐藏基类的同名成员,使得在派生类中无法直接访问被隐藏的基类成员,这种行为叫做隐藏。

隐藏的规则如下:

1.如果派生类中定义了与基类同名的成员函数(包括构造函数和析构函数),则基类的同名成员函数被隐藏。

  • 派生类对象调用同名成员函数时,只能访问派生类中定义的该成员函数,无法访问基类中被隐藏的同名成员函数。(需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
  • 如果希望访问基类中的同名成员函数,可以使用作用域解析运算符::来明确指定基类的名称,如基类名::成员函数名。

2.如果派生类中定义了与基类同名的成员变量,则基类的同名成员变量被隐藏。

  • 在派生类内部,直接使用同名成员变量时,只能访问派生类中定义的成员变量,无法访问基类中被隐藏的同名成员变量。
  • 如果需要访问基类中的同名成员变量,可以通过基类的公有或保护接口进行访问。

隐藏可以帮助解决基类和派生类之间成员的命名冲突问题,同时也提供了灵活性和可扩展性。通过隐藏基类的同名成员,派生类可以在不破坏基类接口的情况下,定义自己的成员函数和成员变量,实现对基类的功能扩展或改进

派生类的默认成员函数

在C++中,派生类可以自动继承基类的构造函数、析构函数和拷贝构造函数,这些被自动继承的构造函数称为派生类的默认成员函数。

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
    的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

  2. 默认构造函数:当派生类没有显式定义构造函数时,编译器会自动生成一个默认构造函数。默认构造函数会调用基类的默认构造函数,如果基类没有默认构造函数,则必须在派生类的构造函数中显式调用基类的构造函数来初始化基类成员。

  3. 拷贝构造函数:当派生类没有显式定义拷贝构造函数时,编译器会自动生成一个拷贝构造函数。拷贝构造函数会调用基类的拷贝构造函数来复制基类成员,如果基类没有拷贝构造函数,则必须在派生类的拷贝构造函数中显式调用基类的拷贝构造函数来复制基类成员。

  4. 析构函数:当派生类没有显式定义析构函数时,编译器会自动生成一个析构函数。析构函数会调用基类的析构函数来销毁基类成员,如果基类有虚析构函数,则需要在派生类中也定义虚析构函数。

需要注意的是,派生类的默认构造函数、拷贝构造函数和析构函数只会自动继承基类的对应函数,如果需要定义其他类型的构造函数或赋值运算符重载函数,则需要显式定义。

继承和友元

继承和友元之间的关系如下:

  • 派生类可以继承基类的友元关系,即派生类可以访问基类的私有成员。
  • 基类不能继承派生类的友元关系,即基类不能直接访问派生类的私有成员。
  • 友元关系独立于继承关系,定义为友元的函数或类可以不涉及继承关系。

菱形继承和菱形虚拟继承

接下来介绍一种C++继承机制中的一种特殊情况菱形继承,它发生在一个派生类同时继承了两个直接或间接基类,而这两个基类又共同继承了同一个基类。这种继承关系看起来像一个菱形,因此被称为菱形继承。
在这里插入图片描述
在图中,我们定义了一个基类 Person,然后让两个派生类 Student 和Teacher都继承自Person ,最后再以 Assistant 类型的派生类同时继承 Student 和 Teacher 两个类。

由于 Student 和 Teacher 都继承自 Person,所以在 Assistant 中会有两份来自 Person 的成员,可能会导致一些问题。例如,如果 Person类中有一个虚函数A,而 Student 和 Teacher 类都重新实现了这个函数,那么 Assistant 类就会有两个 A 函数,这就会造成二义性问题。

为了解决这个问题,C++ 提供了虚继承的机制。通过在 Student 和 Teacher 对 Person 的继承声明中添加关键字 virtual,可以确保只有一份 Person 的实例被共享,从而解决了菱形继承的问题。例如:

class Person {
public:
  virtual void A() {}
};

class Student : virtual public Person {};

class Teacher : virtual public Person {};

class Assistant : public Student, public Teacher {};

总的来说,菱形继承是 C++ 继承机制中的一种特殊情况,可以通过虚继承来解决。虚继承的原理是通过虚基类表来实现的,虚继承会带来一定的性能开销,但只有在菱形继承的情况下才会使用虚继承。因此,在设计类继承关系时需要格外注意菱形继承问题,避免出现二义性和其他不必要的问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/371110.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

优化 IT 支出和消除浪费的 8 种主要方法

不懈追求最佳 IT 支出对于任何组织的长期可持续发展和成功都至关重要。在这个技术快速进步的时代,您必须做出明智的决策,消除浪费,同时最大限度地提高技术投资的价值。 从进行 IT 成本分析到采用敏捷预算和技术标准化,这些策略对…

关于服务器解析A记录和CNAME记录的分析

内容提要: 大致讲下理解,dns域名解析这一块 0 . 问题来源 最近搞了一个七牛云上传,然后需要配置融合cdn加速,也就是可以加速域名,中间有一部需要CNAME 域名,也就是将七牛云提供的域名CNAME一下,查阅资料其实就是起一个别名,好访问而已. 方便我们访问云存储,达到加速的效果. …

Elasticsearch(ES) 简述请求操作索引下文档 增删查改操作

上文 Elasticsearch(ES) 创建带有分词器规则的索引 带着大家创建了一个带有分词功能的索引 老规矩 我们启动一下ES服务 本文 我们就来说说 关于文档的操作 我们先来添加一个文档 就像数据库加一条数据一样 这里 并不需要指定什么表结构和数据结构 它的文档结构是无模式的 添…

es6中标签模板

之所以写这篇文章,是因为标签模板是一个很容易让人忽略的知识点 首先我们已经非常熟悉模板字符串的使用方法 const name "诸葛亮" const templateString hello, My name is ${name}标签模板介绍 这里的标签模板其实不是模板,而是函数调用…

2024年Java面试题大全 面试题附答案详解,BTA内部面试题

基础篇 1、 Java语言有哪些特点 1、简单易学、有丰富的类库 2、面向对象(Java最重要的特性,让程序耦合度更低,内聚性更高) 阿里内部资料 基本类型 大小(字节) 默认值 封装类 6、Java自动装箱与拆箱 装箱就是…

《幻兽帕鲁》解锁基地和工作帕鲁数量上限

帕鲁私服的游戏参数通常可通过配置文件 PalWorldSettings.ini 来进行修改,然而这个配置文件有个别参数对游戏不生效,让人很是头疼。没错!我说的就是终端最大的帕鲁数量! 其实还有另外一种更加高级的参数修改方式,那就…

《Python 网络爬虫简易速速上手小册》第2章:网络爬虫准备工作(2024 最新版)

文章目录 2.1 选择合适的爬虫工具和库2.1.1 重点基础知识讲解2.1.2 重点案例:使用 Scrapy 抓取电商网站2.1.3 拓展案例 1:使用 Requests 和 BeautifulSoup 抓取博客文章2.1.4 拓展案例 2:使用 Selenium 抓取动态内容 2.2 设置开发环境2.2.1 重…

【前沿技术杂谈:开源软件】引领技术创新与商业模式的革命

【前沿技术杂谈:开源软件】引领技术创新与商业模式的革命 开源软件如何推动技术创新开源软件的开放性和协作精神促进知识共享和技术迭代推动关键技术的发展开源软件与新技术的融合 开源软件的商业模式开源软件的商业模式将开源软件与商业软件相结合 开源软件的安全风…

Docker Dockerfile

1、概念介绍 Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。 每条保留字指令都必须为大写字母且后面要跟随至少一个参数 指令按照从上到下,顺序执行 #表示注释 每条指令都会创建一个新的镜像层并对镜像进…

PyTorch 2.2 中文官方教程(十)

使用整体追踪分析的追踪差异 原文:pytorch.org/tutorials/beginner/hta_trace_diff_tutorial.html 译者:飞龙 协议:CC BY-NC-SA 4.0 作者: Anupam Bhatnagar 有时,用户需要识别由代码更改导致的 PyTorch 操作符和 CUDA 内核的变化…

vulhub中AppWeb认证绕过漏洞(CVE-2018-8715)

AppWeb是Embedthis Software LLC公司负责开发维护的一个基于GPL开源协议的嵌入式Web Server。他使用C/C来编写,能够运行在几乎先进所有流行的操作系统上。当然他最主要的应用场景还是为嵌入式设备提供Web Application容器。 AppWeb可以进行认证配置,其认…

【数据结构]排序算法之插入排序、希尔排序和选择排序

简单不先于复杂,而是在复杂之后。 文章目录 1. 排序的概念及其运用1.1 排序的概念1.2 排序运用1.3 常见的排序算法 2. 常见排序算法的实现2.1 插入排序2.1.1 基本思想2.1.2 直接插入排序2.1.3 希尔排序(缩小增量排序) 2.2. 选择排序2.2.1 基本…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Menu组件

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Menu组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Menu组件 TextClock组件通过文本将当前系统时间显示在设备上。支持不同时区的时间…

Ubuntu+GPU搭建Stable-Diffusion教程

【前序】已经安装anaconda 1.git拉取项目到本地 执行git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git 进入项目目录下 cd stable-diffusion-webui/ 2. 安装对应Python依赖包 首先安装pytorch和torchvision,若是GPU环境的用户需要安装与cu…

PHP入门指南:API

PHP入门指南:API 1. 简介2. API的基础概念2.1 什么是API?2.2 API的类型2.3 API的作用2.4 RESTful API2.5 API的基本构成元素 3. PHP与API的交互基础3.1 发送HTTP请求3.2 处理HTTP响应3.3 异常处理3.4 确保安全性 4. 如何在PHP中创建一个简单的API4.1 设计…

ShardingSphere 5.x 系列【5】Spring Boot 3.1 集成Sharding Sphere-JDBC并实现读写分离

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 概述2. 使用限制3. 案例演示3.…

【蓝桥杯选拔赛真题64】python数字塔 第十五届青少年组蓝桥杯python 选拔赛比赛真题解析

python数字塔 第十五届蓝桥杯青少年组python比赛选拔赛真题 一、题目要求 (注:input()输入函数的括号中不允许添加任何信息) 提示信息: 数字塔是由 N 行数堆积而成,最顶层只有一个数,次顶层两个数,以此类推。相邻层之间的数用线连接,下一层的每个数与它上一层左上…

智能设备管理系统:PreMaint助力药厂攻克设备管理难题

在药品生产中,设备管理是确保质量的关键环节。传统的手工操作和纸笔记录方式已经难以适应当今药厂的需求,存在诸多问题。这些问题包括设备管理工作的不成体系,难以随时掌握设备的状态,以及设备无法满足工艺流程的需求。面对这些挑…

【Linux系统化学习】进程等待

目录 进程等待 进程等待的必要性 进程等待的方法 wait方法 等待一个进程(阻塞等待) waitpid方法 任意等待多个进程(阻塞等待) 父进程获取子进程的退出信息 非阻塞轮询等待 进程等待 进程等待的必要性 之前讲过,子进程退…

乐意购项目前端开发 #7

一、购物车 本地购物车 创建cartStore.js文件 创建cartStore.js文件, 将购物车列表数据存在pinia中 import { ref, computed } from "vue"; import { defineStore } from "pinia"; import { useUserStore } from "./user"; import {insertCart…