搞清楚[继承],易如反掌

news2024/11/15 21:43:01

穷不失义,达不离道。——孔丘《论语》


继承

  • 1、简单理解
  • 2、继承
    • 2、1、继承的概念
    • 2、2、继承定义
    • 2、3、基类和派生类对象赋值转换
    • 2、4、继承中的作用域
    • 2、5、派生类默认成员函数
    • 2、6、继承中的特点
      • 2、6、1、友元
      • 2、6、2、静态成员
      • 2、6、3、菱形继承及菱形虚拟继承
  • 3、总结

1、简单理解

封装,继承和多态是C++中不可或缺的组成部分。
封装: 数据和方法放在一起,把想给你访问的定义为公有,不想的定义为私有。就例如:一个类型放到另一个类型里面,通过typedef成员函数调整,封装另一个全新的类型。
继承: 面对对象复用的重要方式->类设计层面上的复用
继承不算是模版,对于模版来说,模版只是一个单纯的一个类,不同的类型,数据类型的不同而已,但是继承不只是类型的区别。
请看一下的图形,第一个表示的是模版的含义,而第二个是继承的含义。
在这里插入图片描述
在这里插入图片描述

多态: 通俗来说,就是多种形态,具体点就是去完成某个行为,不同对象去完成会产生不同的状态。如果想要更具体的案例,那么现实生活中到处都是,就比如买火车票,不同身份的人买的价格都会不一样,相同的人买几等座价格也是不一样的,这就是一个比较典型的多态案例。

继承和多态更细节的地方会在下面说,这里只是简单的概括一下主体。

2、继承

2、1、继承的概念

继承机制是面向对象程序设计使代码能够复用的重要手段,能够允许程序员在保持原有类的特性的基础之上就行扩展,增加内容和功能,这样产生的类成为派生类。继承展现了面对对象程序设计的层次结构,体现了由简单到复杂的认知过程。
与函数的复用相类似,继承是类设计层次的复用。

class Person
{
public:
    void Print()
    {
        cout << "name:" << _name << endl;
        cout << "age:" << _age << endl;
    }
protected:
	string _name = "peter"; // 姓名
	int_age=18; //年龄
};
// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了 Student和Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可 以看到变量的复用。调用Print可以看到成员函数的复用。
class Student : public Person
{ 
protected:
	int _stuid; // 学号 
};

class Teacher : public Person
{
	protected:
	int _jobid; // 工号 
};
int main() 
{
    Student s;
    Teacher t;
    s.Print();
    t.Print();
	return 0; 
}

2、2、继承定义

在这里插入图片描述
派生类和基类的名字是根据程序员自行定义的,无所谓叫什么。
其中继承方式有三种,分别是private,protect和public。
当然继承方式和访问限定符的共同作用下才能知道成员变量或者是成员函数到底有了怎么样子的改变。
在这里插入图片描述

总结:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面 都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。 可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他 成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
  5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡 使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里 面使用,实际中扩展维护性不强。

2、3、基类和派生类对象赋值转换

派生类对象 能够直接赋值给基类的对象/基类的指针/基类的引用。也能够俗称是切片或者是切割。形象的说明,在赋值的时候是派生类是将整个对象就行部分切割之后再赋值给基类,保证基类的正确性,没有多余的部分。
在这里插入图片描述

==基类对象不能赋值给派生类。==很显而易见的是基类的成员并没有多余派生类,如果赋值给派生类,一些部分显而易见的会产生问题,包括但不限于随机赋值,也指针的出现。

2、4、继承中的作用域

每一个成员都有自己的作用域,函数有函数的作用域,变量有变量的作用域,乃至main函数也有自己的作用域,所以继承中的作用域也很重要。
1、继承中的基类和派生类都有独立的作用域。
2、当子类和父类中存在同名函数时,子类成员将会屏蔽父类对同名函数的直接访问,这种情况也叫做隐蔽,也叫重定义
3、成员名相同,就构成隐蔽
4、在设计过程中继承体系最好不要定义同名的成员
这段代码中包含了函数名相同时,出现的隐蔽现象,同时也说明了如果隐蔽了该如何调用基类中的成员函数。

#include<iostream>
#include<string>
using namespace std;
class Person
{
protected:
	string _name = "小李子"; // 姓名
	int _num = 111;
	// 身份证号
};
class Student : public Person
{
public:
	void Print()
	{
		cout << " 姓名:" << _name << endl;
		cout << " 身份证号:" << Person::_num << endl;
		cout << " 学号:" << _num << endl;
	}
protected:
	int _num = 999; // 学号
};
void Test()
{
	Student s1;
	s1.Print();
};
int main()
{
	Test();
	return 0;
}

在这里插入图片描述
这样的结果也能够说明,隐蔽的效果和消除隐蔽的方法。
需要注意的是!这里是隐蔽而不是函数重载,重载和隐蔽是两码事!

2、5、派生类默认成员函数

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认 的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
  5. 派生类对象初始化先调用基类构造再调派生类构造。
  6. 派生类对象析构清理先调用派生类析构再调基类的析构。
  7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加 virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。
    构造时,基类构造再到派生类。析构时显示派生类析构然后再是基类。

2、6、继承中的特点

2、6、1、友元

在基类的定义中可能存在友元,友元的存在在继承中又有什么样的特性呢?
首先,友元是不能够继承的 简单点意思就是你爸爸的朋友不是你的朋友。基类的友元不能够访问子类的私有和保护成员。

2、6、2、静态成员

如果在基类中定义了一个static静态成员,那么整个继承体系中只会有一个这样的成员,无论多少个子类,访问的都是同一个static成员。

2、6、3、菱形继承及菱形虚拟继承

在刚刚讲过的所有的案例中,我们的继承都是按照类似线性的关系来进行继承,但是难免在现实中存在多继承的情况出现。所以一个典型的菱形继承就值得我们来了解并且来分析其中可能存在的问题。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样子的菱形继承就会存在问题,导致一个数据到最后一个类的时候可能会有两个不同的值,不知道该怎么继承,所以菱形继承的问题就是在
1)数据冗余 2)二异性
虽然解决二异性的问题能够在数据前加上限定符来特指某个类中的数据,但是对于数据冗余的问题还是没有解决。
所以这个时候,就需要通过virtual,虚继承的方式来解决问题
virtual在继承过程中就需要加上,如不是最后的时候才加上。
在这里插入图片描述
从内存中能够观察到D对象内部,A,B与C到底怎么储存的,能够类似于类中的函数一样,将A中的a放在最后一个类似于公共的区域,让a只存在一个,改变修改相同的一个a。
那么其中B与C第一行中的那串地址又能代表什么呢,为什么每个的第一行都是一串奇奇怪怪的地址,这究竟是怎么做到能够找到a的地址的呢? 其实就是因为这第一行的地址,才能够让我们找到具体的位置在哪,结下来我们将这串地址放在内存中寻找一下,看看是什么。
在这里插入图片描述
也就是这个样子,找到的位置存放的位置之后可以看到存放的第二个地址的地方的数就是按照从当前位置找到公共位置的地址的距离。这样也就说得通两个地址找到A的位置并且能够得到a的值。
用专业的话来说也就是,通过B,C两个指针指向一张表,这两个表就叫虚基表,两个指针就叫虚基表指针。虚基表中存的偏移量可以找到A。

3、总结

其实继承中复杂的大多是是多继承,多继承中又存在菱形继承,有了菱形继承就又会有菱形虚拟继承,有了菱形虚拟继承底层就会变的复杂。所以一般来说都是不设计多继承,即使有着多继承,也尽量不设计菱形继承,否则在复杂度以及性能上都会存在问题。
并且大多数情况之下,继承也可以换成组合的方式来实现
都能用选组合,其他情况适合什么用什么。
继承的缺点还存在着高耦合的问题。当继承中改变了就会改变后续继承的偶有元素,这样也会造成不少的麻烦,会对后期的修改有较大部分的影响,导致牵一发而动全身的后果。

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

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

相关文章

【开源】基于RMBG的一键抠图与证件照制作系统【含一键启动包】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

2024浙江外国语学院汉语桥线上项目 “在杭州,看见更好的中国”开班

7月9日上午&#xff0c;由教育部中外语言交流合作中心主办、浙江外国语学院国际商学院承办的2024汉语桥“在杭州&#xff0c;看见更好的中国”线上项目正式启动。项目负责人何骅老师及汉语桥教师团队&#xff0c;与来自越南、缅甸、日本、俄罗斯的100名学员相聚云端&#xff0c…

JavaSE学习笔记第二弹——对象和多态(上)

目录 面向对象基础 面向对象程序设计的定义 类的基本结构 成员变量 成员方法 方法定义与使用 设计练习 方法重载 构造方法 静态变量和静态方法 String和StringBuilder 基本含义 区别 总结 今天我们继续来学习JavaSE&#xff0c;扩展和Java相关的知识&#xff0c;…

当CNN遇上Mamba,高性能与高效率通通拿下!

传统视觉模型在处理大规模或高分辨率图像时存在一定限制&#xff0c;为解决这个问题&#xff0c;研究者们就最近依旧火热的Mamba&#xff0c;提出了Mamba结合CNN的策略。 这种结合可以让Mamba在处理长序列数据时既能够捕捉到序列中的时间依赖关系&#xff0c;又能够利用CNN的局…

android自定义键盘弹窗

样式布局 要在Android中自定义键盘弹窗&#xff0c;先要创建一个新的XML布局文件&#xff0c;用于定义键盘弹窗的外观和布局。例如&#xff0c;创建一个名为key_alert_dialog.xml的文件&#xff0c;并在其中添加所需的按钮和其他UI元素。 <?xml version"1.0" e…

7月9日学习打卡-回文链表,交叉链表

大家好呀&#xff0c;本博客目的在于记录暑假学习打卡&#xff0c;后续会整理成一个专栏&#xff0c;主要打算在暑假学习完数据结构&#xff0c;因此会发一些相关的数据结构实现的博客和一些刷的题&#xff0c;个人学习使用&#xff0c;也希望大家多多支持&#xff0c;有不足之…

海外多语言盲盒APP系统开发

随着盲盒的全球化发展&#xff0c;盲盒已经成为了一个热门行业&#xff0c;不仅深受我国消费者的青睐&#xff0c;更是深受海外消费者的喜爱。目前&#xff0c;盲盒出海已经成为了企业拓展市场的新机会。 在数字化时代&#xff0c;海外盲盒APP为企业提供了一个快速打开海外盲盒…

57、基于概率神经网络(PNN)的分类(matlab)

1、基于概率神经网络(PNN)的分类简介 PNN&#xff08;Probabilistic Neural Network&#xff0c;概率神经网络&#xff09;是一种基于概率论的神经网络模型&#xff0c;主要用于解决分类问题。PNN最早由马科夫斯基和马西金在1993年提出&#xff0c;是一种非常有效的分类算法。…

MyBatis框架学习笔记(一):MyBatis入门

1 MyBatis 介绍 1.1 官方文档 MyBatis 中文手册&#xff1a; &#xff08;1&#xff09;https://mybatis.org/mybatis-3/zh/index.html &#xff08;2&#xff09;https://mybatis.net.cn/ Maven 仓库&#xff1a; https://mvnrepository.com/ 仓库作用&#xff1a;需要…

android Dialog全屏沉浸式状态栏实现

在Android中&#xff0c;创建沉浸式状态栏通常意味着让状态栏背景与应用的主题颜色一致&#xff0c;并且让对话框在状态栏下面显示&#xff0c;而不是浮动。为了实现这一点&#xff0c;你可以使用以下代码片段&#xff1a; 1、实际效果图&#xff1a; 2、代码实现&#xff1a;…

第一次坐火车/高铁,如何坐?全流程讲解

第一次坐动车注意事项 第一次乘动车流程&#xff1a;进站→安检→候车厅→找检票口→过闸机→站台候车→找车厢→上车找座→下车→出站 乘车流程 一、进火车站/高铁站&#xff1a;刷购票证件原件进站 1、自助闸机刷证&#xff1a;身份证 2、人工通道&#xff1a;护照、临时…

Oracle通过procedure调用webservice接口

文章目录 准备工作方法体如下Oracle语句详情重要参数说明Web Service的URL地址构造SOAP请求包体构造SOAP请求包体方法依次如下操作即可&#xff1a; 如果需要把上面的功能变成function或者procedure&#xff0c;请自行搜索相关的方法实现即可。 准备工作 定义测试的webservice…

怎么将图片旋转30度?旋转图片的几种方法推荐

怎么将图片旋转30度&#xff1f;在创作过程中&#xff0c;我们常常需要处理图片的镜像效果&#xff0c;确保其视觉效果和构图都达到最佳状态。镜像效果的合理运用不仅可以解决视觉单调的问题&#xff0c;还能在艺术作品中吸引观者的注意力。此外&#xff0c;镜像可以有效地调整…

MoRA: High-Rank Updating for Parameter-Efficient Fine-Tuning

文章汇总 LoRA的问题 与FFT相比&#xff0c;低秩更新难以记忆新知识。虽然不断提高LoRA的秩可以缓解这一问题&#xff0c;但差距仍然存在。 动机 尽可能地利用相同的可训练参数来获得更高的 Δ W \Delta W ΔW秩。 考虑到预训练权值 W 0 ∈ R d k W_0\in R^{d\times k} W0​…

Mac电脑上有什么好玩的肉鸽游戏推荐 苹果电脑怎么玩以撒的结合

Mac电脑尽管在游戏兼容性上可能不及Windows。但是&#xff0c;对于喜欢在Mac上游玩的玩家来说&#xff0c;依然有不少优秀的游戏可以选择&#xff0c;尤其是那些富有挑战性和策略性的肉鸽游戏。此外&#xff0c;对于经典游戏《以撒的结合》&#xff0c;Mac平台也提供了良好的游…

原创作品—数据可视化大屏

设计数据可视化大屏时&#xff0c;用户体验方面需注重以下几点&#xff1a;首先&#xff0c;确保大屏信息层次分明&#xff0c;主要数据突出显示&#xff0c;次要信息适当弱化&#xff0c;帮助用户快速捕捉关键信息。其次&#xff0c;设计应直观易懂&#xff0c;避免复杂难懂的…

论文 | Chain-of-Thought Prompting Elicits Reasoningin Large Language Models 思维链

这篇论文研究了如何通过生成一系列中间推理步骤&#xff08;即思维链&#xff09;来显著提高大型语言模型进行复杂推理的能力。论文展示了一种简单的方法&#xff0c;称为思维链提示&#xff0c;通过在提示中提供几个思维链示例来自然地激发这种推理能力。 主要发现&#xff1…

飞睿智能会议室静止雷达人体检测传感器,实时监测使用状态,有人、无人智能感应节能减

在这个科技日新月异的时代&#xff0c;每一个细微的创新都可能成为推动行业创新的关键力量。今天&#xff0c;让我们聚焦于一项看似不起眼却实则潜力无限的技术——飞睿智能静止雷达人体检测传感器&#xff0c;以及它在会议室这一商务交流核心区域中的巧妙应用。想象一下&#…

嵌入式c语言——指针加修饰符

指针变量可以用修饰符来修饰