C++继承与多态

ESP32实战指南:SPI驱动ADXL345三轴加速度传感器的精准数据采集与姿态解算 本文详细介绍了如何使用ESP32通过SPI接口驱动ADXL345三轴加速度传感器,实现精准数据采集与姿态解算。从硬件连接到SPI通信优化,再到数据处理和低功耗策略,提供了全面的实战指南。特别适合物联网开发者和硬件工程师参考,帮助快速掌握传感器数据采集技术。 阅读详情


前言

本文介绍了C++继承与多态,基于施磊老师的C++课程。


一、继承的基本意义

父类和子类可以有同名的成员变量,用作用域区分。
在这里插入图片描述

继承方式以及成员变量的访问权限:
在这里插入图片描述

总结:
1、外部只能访问对象public的成员,protected和private的成员无法直接访问
2、在继承结构中,派生类从基类可以继承过来private的成员,但是派生类却无法直接访问
3、protected和private的区别?在基类中定义的成员,想被派生类访问,但不想被外部访问,那么在基类中,把相关成员定义为protected保护的;如果派生类和外部都不打算访问,那么在基类中,就把相关成员定义为private私有的。

二、重载、隐藏、覆盖

1、重载
一组函数重载,必须处于同一个作用域中;并且函数名字相同,参数列表不同

2、隐藏
在继承结构中,派生类的同名成员,把基类中的同名成员给隐藏调用了

对于基类和派生类之间的转换,一般只支持从派生类转化为基类(即从下到上的转换)
在这里插入图片描述

三、虚函数、静态绑定和动态绑定

1、一个类里面定义了虚函数,那么编译阶段,编译器给这个类类型产生一个唯一的vftable虚函数表,虚函数表中主要存储的内容就是RTTI指针和虚函数的地址。当程序运行时,每一张虚函数表都会加载到内存的.rodata区。

2、一个类里面定义了虚函数,那么这个类定义的对象,在其运行时,内存中的开始部分,会多存储一个vfptr虚函数指针,指向对应类类型的虚函数表。一个类定义的n个对象,他们指向的都是同一张虚函数表。

3、一个类里面虚函数的个数,不影响对象内存的大小,影响的是虚函数表的大小。

4、如果派生类中的方法,和基类继承来的某个方法,返回值、函数名、参数列表都相同,而且基类的方法是virtual虚函数,那么派生类的这个方法,自动处理成虚函数
在这里插入图片描述

对于派生类中和基类中相同的函数,会在派生类的虚函数表中将对应表项覆盖:
在这里插入图片描述

在这里插入图片描述

四、虚析构函数

Q1、哪些函数不能实现成虚函数?
虚函数依赖:

  1. 虚函数能产生地址,存储在虚函数表中
  2. 对象必须存在(即通过虚函数指针找到虚函数表,再通过虚函数表找到虚函数地址)

构造函数不能成为虚函数,因为在调用构造函数时,对象尚未存在,也就无法通过虚函数指针查找虚函数表。
其次,在构造函数中调用虚函数也不会发生动态绑定。

static静态成员方法也不能成为虚函数,static成员方法的调用不依赖对象

Q2、为什么应当将析构函数实现成虚函数?

当我们使用基类指针指向堆上开辟的派生类类型的对象时,如果对基类指针delete,就会导致只调用基类的析构函数,不调用派生类的析构函数,发生问题:

#include <iostream>

using namespace std;

class Base
{
public:
    Base(int data) : ma(data) { cout << "Base()" << endl; }
    ~Base() { cout << "~Base()" << endl; }
private:
    int ma;
};

class Derive : public Base
{
public:
    Derive(int data) : Base(data), mb(data) { cout << "Derive()" << endl; }
    ~Derive() { cout << "~Derive()" << endl; }
private:
    int mb;
};

int main()
{

    Base* pb = new Derive(10);
    delete pb;

    /*
    输出:
        Base()
        Derive()
        ~Base()
    */
    return 0;
}

将基类的析构函数实现为虚函数即可:

virtual ~Base() { cout << "~Base()" << endl; }

在这里插入图片描述

五、再谈动态绑定

Q:是不是虚函数的调用就一定是动态绑定?

不是,在类的构造函数中,调用虚函数,也是静态绑定。

此外,直接用对象本身调用虚函数也不会发生动态绑定。

要发生动态绑定,需要使用指针或者引用。

六、理解多态

Q:如何解释多态?
静态(编译时期)多态:
函数重载、模板(函数模板、类模板)

动态(运行时期)多态:
在继承结构中,基类指针(引用)指向派生类对象,通过该指针(引用)调用同名覆盖方法(虚函数),基类指针指向哪个派生类的对象,就会调用哪个派生类对象的同名覆盖方法,称为多态。

笔试题:
待补充

七、理解抽象类

拥有纯虚函数的类叫做抽象类,抽象类不能在实例化对象,但是可以定义指针或者引用变量。

//纯虚函数
virtual void func() = 0;

八、理解虚基类和虚继承

virtual关键字:
1、修饰成员方法表示虚函数
2、修饰继承方式表示虚继承。被虚继承的类称作虚基类。
虚继承中的派生类不仅会存储自己的虚函数表vftable,还会存储一个用于 指向 指示基类数据的vbtable 指针vbptr。

在这里插入图片描述
基类指针指向派生类对象,永远指向的是派生类中基类部分数据的起始地址:

在这里插入图片描述

九、菱形继承

虚继承可以用于解决菱形继承的问题,参考这篇文章:菱形继承

十、C++的四种类型转换

1、const_cast: 去除常量属性的类型转换
a.需要类型匹配,不像C能够进行强制转换。
b.只能用于指针或者引用

const_cast是语言级别的,看不到源码实现,从汇编代码上来看和C的强制转换是一样的。

const int a = 10;
int *p0 = const_cast<int*>(&a);         // 编译正确
double *p1 = (double*)&a;               // 编译正确
double *p2 = const_cast<double*>(&a);   // 编译错误
int p3 = const_cast<int>(a);            // 编译错误

2、static_cast:提供编译器认为安全的类型转换

没有任何联系的类型之间进行转换会被否定:

int p = 10;
// 以下三行均编译正确
int b0 = static_cast<int>(p);
char b1 = static_cast<char>(p);
double b2 = static_cast<double>(p);

// 以下两行均编译错误
int *p1 = nullptr;
short *c1 = static_cast<short*>(p1);
double *c2 = static_cast<double*>(p1);

对于基类类型和派生类类型之间的static_cast转换,一般都是可以的,因为二者之间有关联

3、reinterpret_cast:类似于C风格的强制类型转换

4、dynamic_cast:主要用于继承结构中,可以支持RTTI类型识别的上下转换

#include<iostream>

using namespace std;

class Base {
public:
    virtual void func() { cout << "Base::func()" << endl; }
};

class Derive1 : public Base {
public:
    void func() { cout << "Derive1::func()" << endl; }
};

class Derive2 : public Base {
public:
    void func() { cout << "Derive2::func()" << endl; }
    void derive2Func() { cout << "Derive2::derive2Func()" << endl; }
};

void showFunc(Base *p) {
    // dynamic_cast会检查p指针是否指向的是一个Derive2类型的对象
    // 返回Derive2对象的地址,如果不是Derive2类型,返回nullptr
    Derive2 *pd2 = dynamic_cast<Derive2*>(p);
    if (pd2 != nullptr) {
        pd2->func();
    } else {
        p->func();
    }
}

int main()
{
    Derive1 d1;
    Derive2 d2;
    showFunc(&d1);
    showFunc(&d2);
    return 0;
}
《30天入门 SAP BTP 开发》教程的目录和使用说明,建议收藏 本教程分为两部分:第一部分为SAP BTP入门系列,包含从基础概念到操作步骤的系统性学习内容,建议零基础用户按顺序学习;第二部分为专题文章集合,涵盖SAP BTP的多个技术点,适合已有基础的用户按需查阅。教程包含账号申请、Global Account操作、Java应用开发、AI工具使用等丰富内容,同时解答常见问题并提供实战案例。所有文章均附带详细链接,便于读者系统学习或针对性查阅。 阅读详情

相关推荐

基于 SquashFS 构建 Linux 可读写文件系统

嵌入式 Linux 启动过程 本文所描述的的 Linux Image 由 BootLoader、kernel、initrd、rootfs 组成,它们共同存在于一个可以启动的存储设备中(本文以 USB 为例)。组成架构如下: 图 1. 可启动 linux 镜像文件结构 各个模块的作用如下: Boot Loader:由 BIOS 加载,用于将后续的 Kernel 和 initrd 的装载到内存中 kernel:为 initrd 运行提供基础的运行环境 initrd:检测并加载各种驱动程序 ro

wzq2009的专栏 1174

C++ 继承和多态

讲解继承和多态,多态的实现原理

凡事都是靠练习 3338

Gephi实战指南——从数据导入到可视化输出

本文详细介绍了Gephi数据可视化工具的使用方法,从数据导入到可视化输出的全流程实战指南。涵盖Gephi三大工作区功能、数据导入技巧、图形编辑进阶操作以及专业级可视化输出方案,帮助用户高效完成社交网络分析等复杂任务。

weixin_28731223的博客 481

【C++】继承与多态

C++继承与多态万字详解!!

Pursue quality, not quantity. 2257

思科模拟器Cisco Packet Tracer交换机的管理配置

一、交换机的管理方式:带内管理和带外管理 通过交换机的 Console 端口管理交换机属于带外管理;这种管理方式不占用交换机的网络端口,第一次配置交换机必须利用 Console 端口进行配置。 通过 Telnet、拨号等方式属于带内管理。 二、控制台配置思科交换机 1.新建拓扑图 新建拓扑,选择console线连接交换机和PC,一端接交换机的console口,一端接PC的RS 232 口(...

qq_37992321的博客 2万+

单细胞分析避坑指南:SCTransform和Harmony参数设置详解

本文深入解析了单细胞分析中SCTransform标准化与Harmony批次校正的关键参数设置。针对10x Genomics等数据,详细探讨了如何通过调整`vars.to.regress`、`theta`等核心参数,在有效去除技术噪音的同时,避免过度校正以保留关键的生物学差异,从而提升分析结果的可靠性与可解释性。

weixin_29053073的博客 608

C++——继承和多态

多态: 多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。 C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。 多态性是面向对象程序设计的关键技术之一。若程序设计语言不支持多态性,不能称为面向对象的语言。利用多态性技术,可以调用同一个函数名的函数,实现完全不同的功能。 1.1两种多态: 1.1.1编译时多态(早绑定): 编译时的多态通过函数的重载和运算符的重载来实现的。 就像是未出生的男女孩定下的娃娃亲。 1.1.2运行时多态(晚绑定)

weixin_57133901的博客 2627

Windows Server 2019/2022 RDS 授权实战:3步激活许可证服务器,解决120天宽限期问题

本文详细介绍了Windows Server 2019/2022 RDS授权实战,提供3步激活许可证服务器的完整解决方案,解决120天宽限期问题。涵盖远程桌面授权服务器配置、许可证激活方法及组策略设置,确保企业合规使用远程桌面服务。

weixin_32705179的博客 974

C++中的继承与多态

本文深入探讨了C++中的类继承机制,解释了继承的基本概念、语法格式及其在工程中的应用。文章详细介绍了类继承的三种方式(public、protected、private)及其对访问权限的影响,强调了public继承的广泛适用性。此外,文章还讨论了基类与派生类之间的赋值兼容性、内存切片现象以及继承中的作用域问题。通过示例代码和图示,文章展示了继承中可能出现的特殊现象,如隐藏和覆盖,并提供了实际代码运行结果以加深理解。最后,文章总结了继承在C++编程中的重要性,强调了其在扩展类功能和提高代码复用性方面的优势。

m0_73987904的博客 2110

开源低场MRI系统构建:从原理到三天实现

磁共振成像(MRI)作为现代医学影像的核心技术,其高场强系统存在成本和技术门槛问题。低场MRI通过开源硬件和模块化设计实现技术民主化,采用永磁体替代超导磁体可大幅降低系统复杂度。本文以H型永磁体设计为例,结合MaRCoS开源控制库和PyPulseq脉冲序列工具,展示了如何快速构建教育级MRI系统。关键技术包括遗传算法优化的匀场方案、CNC加工的梯度线圈,以及基于Red Pitaya的SDR控制架构。这种轻量化方案特别适合医学物理教学和脉冲序列开发验证,为MRI技术在资源有限地区的普及提供了新思路。

weixin_30470643的博客 449

华为OD机试 - 文件存储系统的排序 - 深度优先搜索dfs(Java 双机位C卷 200分)

华为OD机试 双机位C卷题库疯狂收录中,刷题。

学Java,找哪吒 719

C++封装、继承、多态

C++封装继承多态总结 面向对象的三个基本特征 面向对象的三个基本特征是:封装、继承、多态。其中,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用! 封装

ruyue_ruyue的专栏 10万+

AMD机密计算虚拟机介绍

AMD机密计算虚拟机介绍

木简熙的博客 524

C++中的继承与多态_多态

C++中的继承与多态2 1. 多态的概念 1.1 概念 2. 多态的定义及实现 2.1多态的构成条件 ​编辑2.2 虚函数 2.3虚函数的重写 2.4 C++11 override 和 final 2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类 3.1 概念 3.2 接口继承和实现继承 4.多态的原理 4.1虚函数表 4.2多态的原理 4.3 动态绑定与静态绑定 5.单继承和多继承关系的虚函数表 5.1 单继承中的虚函数表 5.2 多继承中的虚函数表 5

2301_79746169的博客 1623

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【C++】继承和多态

继承的定义格式如下,Person是父类/基类Student是子类/派生类public为继承方式继承和组合public继承是一种is-a的关系。也就是说每个子类对象都是一个父类对象。组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。什么是组合呢?如下代码就是组合,其中是B组合了Aclass Apublic:int _a;A a;优先使用对象组合,而不是类继承。继承允许我们根据父类的实现来定义子类的实现。

YoungMLet的博客 1135

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++继承和多态

继承我们可以理解为是一种手段,我们是不是可以从其他的地方继承一些东西来供自己使用,继承是面向对象程序设计使代码可以复用的一个很重要的手段。我们可以再保持原有类特性的基础上进行扩展,增添一些其他的功能,而这种新产生的类,就叫做派生类。class Person //基类public:protected:private:class Student : public Person //派生类protected:int main()Student s;

2402_84602321的博客 1990

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

C++之继承&多态

继承 继承之形 继承的作用域 继承的构造与析构 多继承 菱形继承 多态 多态之形 final和override(C++11) 纯虚函数&抽象类 多态的原理 打印虚表(在vs2022中) 多继承下的虚表 菱形虚继承中埋的坑 静态多态与动态多态 我对虚函数和普通成员函数调用区别的理解 问答题 结语

Steve__evetS的博客 1367

继承与多态实战:CPP-Crash-Course中的高级C++特性

在C++编程中,继承与多态是面向对象编程的核心特性,它们能够显著提升代码的复用性和扩展性。CPP-Crash-Course项目通过清晰的示例代码,展示了如何在实际开发中应用这些高级特性。本文将带你深入理解继承与多态的概念,并通过项目中的实例代码,掌握它们的实际应用技巧。 ## 继承:代码复用的基石 继承允许我们创建新类(派生类)来继承现有类(基类)的属性和方法,从而实现代码的复用和扩展。在CP

gitblog_00025的博客 820

c++继承与多态

本次博客主要讲解继承与多态的基本概念,以及一些注意事项。1 必须要有继承关系。2 只能是基类的指针或者是引用去调用函数3 必须构成重写关系,被调用的函数必须得是虚函数。虚函数的概念:被virtual修饰的成员函数就是虚函数。虚函数的重写:虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

comeonworld的博客 895

C++的封装、继承、多态

C++封装、继承、多态总结

Albert_weiku的博客 2298

C++ 02 继承与多态

虚函数的详细解释 虚函数表和虚函数指针的关系 动态多态的实现

xiaozhangcxy的博客 1222

C++:组合、继承与多态

class 基类名virtual 返回值类型 将要在派生类中重载的函数名(参数列表);例如,用虚函数修改上例class Apublic:public:public:i.play();tune(b);C c;tune(c);A* p = &b;tune(*p);p = &c;tune(*p);A a;tune(a);return 0;

weixin_45652283的博客 1298

C++多态与继承

C++多态与继承 C++中多态分为静态多态和动态多态, 静态多态:编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推 断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。动态多态:在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。实现动态多态的条件:1、必须是虚函数,派生类中必须重写虚函数 2、必须是通过基类

sigma_inf的博客 725

C++ 继承与多态详解

本文系统讲解了C++继承与多态的核心概念。重点介绍了三种继承方式(public/protected/private)的权限控制差异,深入剖析了派生类对象的构造/析构顺序,强调虚析构函数在多态删除时的重要性。详细对比了静态多态(重载、模板)和动态多态(虚函数、抽象类)的实现机制,特别分析了虚函数表的底层原理。同时指出了切片问题的产生场景及多重继承中的二义性问题解决方案。通过继承实现代码复用,借助多态实现运行时行为差异化,是C++面向对象编程的关键技术。

My__Space的博客 1069
上一篇: C++运算符重载
下一篇: C++ STL
hongyunone
博客等级 码龄7年 108粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值