C++ —— 继承

什么是继承?

继承是指一种代码可以被复用的机制,在一个类的基础上进行扩展,产生的新类叫做派生类,被继承的类叫基类。(也可称为子类和父类)

继承的写法:

class B : 继承方式 A              (类B以public/private/protected的方式继承类A)

当需要继承多个类时:

 class C : 继承方式 A B              (类C以public/private/protected的方式继承类A、B)

注意:谁在前就先继承谁,如上则是先继承A再继承B

继承究竟做了什么?

继承继承,顾名思义就是继承了父类的成员(准确的说是会继承除去析构、构造以外所有的成员)再加上子类的扩展形成新类。

如下图:(请先忽略构造函数部分)子类student继承了父类people的_name和_age,所以这个子类中也有_name和_age成员变量。

继承的特性

继承方式

(父类XX成员以XX继承后,在子类是XX成员)

类成员/继承方式publicprotectedprivate
父类的public成员子类的public成员子类的protected成员子类的private成员
父类的protected成员子类的protected成员子类的protected成员子类的private成员
父类的private成员在子类中不可见在子类中不可见在子类中不可见

 总结:在继承方式和原本的成员权限中选权限更小的,如在父类中为public以protected继承则继承后的权限为protected(权限大小:public<protected<private)

虽然继承方式有三种,但常用的却只有public。

切片

在继承中,往往可以进行用子类对象直接调用父类函数的情况。像前者这种情况往往发生在相似类型身上,因为相似所以可以转换。而父类有的,子类都有,所以程序执行时就会把子类中与父类相同的部分拿出来去调用函数,这种情况就叫切片。

 

例如:将Student的对象s拿去给People的对象p去调用拷贝构造就是使用了切片的特性

子类构造与析构

虽说父类有的子类都有,理论上说构造自己搞定进行,但规定上在构造子类对象时要先调用父类构造函数,再构造子类部分。(继承是一种复用代码的机制,这里也是复用的父类构造,减少了工作量)

这就是为什么Student的构造函数中的初始化列表要调用  People(string name,int age)  这个构造(这个过程同样会发生切片)

构造要手动调用,那析构也要吗? 

手动调用时结果父类部分析构了两次。实际上在子类析构结束后会自动调用父类析构去释放子类中与父类一致的部分,不需要去手动调用。

隐藏(重定义)

当父类与子类出现同名的成员变量或成员函数时,子类成员将屏蔽对父类成员的直接访问,这时通过子类对象去访问这个同名成员时优先访问子类的。

class People
{
public:void printf(){cout << _name << " " << _age << endl;}People(string name, int age):_name(name),_age(age){}People(People& p):_name(p._name),_age(p._age){}~People(){cout << "~People()" << endl;}string _name;int _age;
};class Student : public People 
{
public:void printf(){cout << _name << " " << _age << " "<< _Sno<<endl;}Student(string name, int age, int sno):People(name, age),_Sno(sno){}~Student(){cout << "~Student()" << endl;}//学号int _Sno;
};int main()
{Student s("swi",20,34);s.printf();return 0;
}

 之所以会出现隐藏这种特性与他的搜索逻辑有关,当我们通过子类对象访问成员时,会先去子类中寻找这个成员,如果没找到再去父类中寻找。


以上所讲都是继承的通用的特性,样例均为单继承

多继承

多继承顾名思义就是继承多个类。

class A
{
public:void printf(){cout << _a << endl;}int _a = 1;
};class B
{
public:void printf(){cout << _b << endl;}int _b = 2;
};//C同时继承了类A和类B(先继承的A,后继承的B)
class C:public A,B
{
public:void printf(){cout << _c << endl;}int _c = 3;
};int main()
{C* c = new C;return 0;
}

查看内存后我们发现,缺省值为1的_a在缺省值为2的_b 的前面,class C:public A,B的顺序能够决定谁先被继承。

 A,B反过来后:

多继承的问题

 假设他们的成员变量分别为_a,_b,_c,_d,那么他们在内存中的存储会如下图:

此时就会出现两个问题:

  • 二义性:当我访问_a时,到底访问哪一个_a。
  • 数据冗余:出现重复数据,占用不必要空间 

解决方法

在继承方式前加上关键字virtual构成虚继承(注意:想要解决菱形继承的问题,放virtual关键字的类是出现重复部分的若干个子类,被virtual修饰的子类的父类称作虚基类

如下图的菱形问题(菱形问题是这类问题的总称,并不一定是菱形):

不处理时:

 使用virual处理后:

虚基类的成员将会在下方找到一片公共空间去存储,这样一来就解决了二义性和数据冗余。

但是原来两条红线存储的又是什么?

将这四行数字重新组合排序可以得到两个地址,去查找这个地址,发现他分别存储了一个十六进制的28,一个十六进制的18。实际上这个地址是虚基表的地址,而虚基表存储的是地址偏移量,该类的部分的起始地址加上偏移量就能找到虚基类的成员变量_a。

 

多态

对不同的对象会有不同的实现方法,即为多种形态。

多态的条件:

  1. 虚函数的重写(父子类虚函数需要三同,三同指函数名、参数、返回值)
  2. 父类的指针或引用去调用

 但是有三种例外:

  1. 协变(基类与派生类的虚函数返回值不同)
  2. 析构函数的重写(看似不符合函数名相同的条件,实际上编译器对其进行了特殊处理,编译后析构函数的名字统一处理成destructor)
  3. 派生类虚函数重写可以不加virtual(但建议写上)

虚函数

virtual修饰的函数叫做虚函数,虚函数只能是类中非静态的成员函数。

虚函数的重写

子类和父类中的虚函数拥有相同的名字,返回值,参数列表,那么称子类中的虚函数重写了父类的虚函数,或者叫做覆盖。(虚函数重写,重写的是函数体)

//成人
class People
{
public:virtual void fun(){cout << "全票" << endl;}
};//儿童
class Child : public People 
{
public:virtual void fun(){cout <<"半票" << endl;}
};void buyTicket(People& p)
{p.fun();
}int main()
{People p;Child c;buyTicket(p);buyTicket(c);return 0;
}

多态的原理

为什么会访问到不同的虚函数? 

使用父类的指针或引用去调用(用子类来调用就会产生切片),根据其指针或引用可以找到其对应的虚函数表,进而找到虚函数地址然后去调用不同的虚函数。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java高级阶段面试题库(Redis数据库、MQ消息队列、kafka、SpringBoot + SpringCloud、MySQL、JVMJUC、其它)

文章目录 1. Redis数据库篇(忽略)1.1 简单介绍一下redis1.2 单线程的redis为什么读写速度快?1.3 redis为什么是单线程的?1.4 redis服务器的的内存是多大?1.5 为什么Redis的操作是原子性的&#xff0c;怎么保证原子性的&#xff1f;1.6 你还用过其他的缓存吗&#xff1f;这些…

学习Django

1.python安装是会有几个主要目录&#xff1a; 2.如果某个路径加入了环境变量&#xff0c;那么在命令行直接输入他下面的文件就能找到&#xff0c;不用输入完整路径 2.过程 &#xff08;1&#xff09;安装 &#xff08;2&#xff09;建项目 在终端&#xff1a; &#xff08;…

快速回复app是什么样

在电商领域&#xff0c;掌握一些必备的软件工具是提高工作效率、优化运营流程以及提升用户体验的关键。本文将为您介绍做电商必备的几个软件&#xff0c;帮助您更好地开展电商业务。 ​ 快速回复APP&#xff1a;重新定义沟通效率 在快节奏的现代社会中&#xff0c;人们对于沟通…

ZeRO论文阅读

一.前情提要 1.本文理论为主&#xff0c;并且仅为个人理解&#xff0c;能力一般&#xff0c;不喜勿喷 2.本文理论知识较为成体系 3.如有需要&#xff0c;以下是原文&#xff0c;更为完备 Zero 论文精读【论文精读】_哔哩哔哩_bilibili 二.正文 1.前言 ①为什么用该技术&…

Linux网络设置

将Linux主机接入到网络&#xff0c;需要配置网络相关设置 一般包括&#xff1a;主机名&#xff1b;IP/netmask&#xff1b;路由&#xff1a;默认网关&#xff1b;DNS服务器&#xff1a;主DNS服务器&#xff0c;次DNS服务器&#xff0c;第三个DNS服务器 网卡的配置文件在&…

java:观察者模式

java&#xff1a;观察者模式 1 前言 观察者模式&#xff0c;又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;他定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时&#xff0c;会通知所…

百面算法工程师 | 卷积基础知识——Convolution

目录 8.1 图像卷积过程 8.2 卷积层基本参数 8.3 卷积后图像的长和宽大小的计算方式 8.4 卷积神经网络中的权重共享 8.5 上采样中的反卷积 8.6 空洞卷积 8.7 深度可分离卷积 8.8 为什么可分离卷积中Depthwise卷积后还要进行pointwise卷积 8.9 分组卷积 Group Conv 8.1…

AI视频教程下载:ChatGPT个人生产力提升指南

在本课程中&#xff0c;您将学习如何成功地将ChatGPT融入您的工作和生活&#xff0c;以优化您的社交媒体内容并扩展您的业务。 您将学习如何使用ChatGPT自动创建、校对、总结和翻译文本&#xff0c;以及如何与机器人沟通以实现您的目标。 您还将学习如何创建jQuery代码、编程…

倪海厦是怎么去思考问题的(一)下

1《天纪》是自然法则 2自然法则是个《真理》 3《真理》不需要再证实 4《真理》没有二元对立 紧接着第三点&#xff1a;真理不需要再去证实。现在有很多的人呢&#xff0c;看书学习&#xff0c;自认为自己很聪明&#xff0c;总要去证实一些东西。证明谁的说法是错的&#xff…

麒麟龙芯loongarch64 electron 打包deb包

在麒麟龙芯&#xff08;loongarch64&#xff09;电脑上 使用electron 开发桌面应用。之前用electron-packager 打包出来的是文件夹 是 unpack 包。现在需要打包deb包&#xff0c;依据开发指南开始打包。 在项目文件夹下 打开终端 输入 npm run packager 先打包unpack包 然后…

ATFX汇市:澳大利亚一季度CPI年率大降,澳元升值态势延续

▲ATFX图 据澳大利亚统计局数据&#xff0c;第一季度CPI年率最新值3.6%&#xff0c;相比前值4.1%大降0.5个百分点&#xff0c;但仍高于3.5%的预期值。历史数据看&#xff0c;自从2022年四季度创出7.8%阶段性高点之后&#xff0c;澳大利亚的季度CPI年率就保持着稳定的下降态势。…

翻译《The Old New Thing》 - Why are HANDLE return values so inconsistent?

Why are HANDLE return values so inconsistent? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20040302-00/?p40443 Raymond Chen 2004年01月27日 简介 在处理 Windows 编程中的句柄时&#xff0c;开发者需要面对的一个挑战是不同函数可…

SWCTF

easy_php 源码 <?php// flag is in flag.php highlight_file(__FILE__); ini_set(display_errors, 0); error_reporting(0);if (isset($_GET[myon1]) && isset($_GET[myon2]) && isset($_GET[myon3])) {$myon1 $_GET[myon1];$myon2 $_GET[myon2];$myon…

苍穹外卖day12 (Apache POI) 数据统计-Excel报表

文章目录 前言一、工作台1.1 今日数据1.1.1 接口设计1.1.2 代码实现 1.2 订单管理接口1.3菜品总览接口1.4 套餐总览接口1.5 订单搜索&#xff08;已完成&#xff09;1.6 各个状态的订单数量统计&#xff08;已完成&#xff09; 二、Apache POI2.1 概述2.2 效果展示 三、导出运营…

vue中web端播放rtsp视频流(摄像头监控视频)(海康威视录像机)

一、ffmpeg安装​​​​​​ ffmpeg下载 https://ffmpeg.org/download.html找ffmpeg-release-essentials.zip点击下载&#xff0c;下载完解压ffmpeg.exe 程序运行 二、配置ffmpeg环境变量 添加成功后验证是否生效任意地方打开cmd窗口输入 ffmpeg 打印如下表示成功 三、node…

未来五十年,智能科技将如何改变传统行业格局?

未来五十年内&#xff0c;随着人工智能&#xff08;AI&#xff09;和智能科技的不断发展&#xff0c;许多行业将面临被取代的风险。虽然这种趋势可能会带来一些担忧&#xff0c;但也将为人类社会带来巨大的变革。下面将详细探讨哪些行业可能会在未来被智能科技所取代。 ▶ 制造…

利用弹性云主机部署高效数据库系统

在当今云计算的时代&#xff0c;弹性云主机&#xff08;EC2&#xff09;为我们提供了前所未有的灵活性和可扩展性&#xff0c;使得在云端部署高效的数据库系统成为可能。本文将从选择适当的云服务配置、优化数据库设置、建立完备的数据备份与恢复策略&#xff0c;以及加强数据库…

ardupilot开发 --- Jetson Orin Nano 篇

多情应笑我早生华发 0. 一些概念1. 系统安装&#xff08;刷机、flash&#xff09;1.1 使用SD卡安装系统1.2 使用固态硬盘安装系统 0. 一些概念 官网&#xff1a;https://www.nvidia.com/en-us/ Developers Documentation Getting Started Jetson Developer Kits User Guid…

「C++ 内存管理篇 1」C++动态内存分配

〇、C语言的动态内存分配方式 关于C语言的动态内存分配方式&#xff0c;简单来讲就是使用四个库函数&#xff1a;malloc、calloc、 realloc、free对堆区的内存进行灵活的分配和回收。有兴趣的话可以看看这篇文章: 「C语言进阶1」动态内存分配 一、C的动态内存分配方式 1. 什么…

国产大模型各自优势如何?大家都怎么选?

近日&#xff0c;一份国产大模型排行榜在网上流传&#xff0c;显示文心一言、通义千问、Kimi位居前三名&#xff0c;其中文心一言用户数为2亿&#xff0c;与其他产品拉开明显差距&#xff1b;前三名月访问量总计超过3000万。国内大模型也开始出现分化效应。