c++的继承

封装、继承和多态是c++的三大特性,他们的关系甚为紧密

封装的概念简单易懂,其实就是将数据和操作数据的方法结合在一起,形成一个独立的单元(类)通过访问控制符(如privateprotectedpublic),封装可以隐藏内部实现细节,只暴露必要的接口,使得外部代码无法直接访问内部数据,从而提高了安全性和代码的可维护性

首先需要了解什么是继承

1.继承的概念和定义 

1.1继承的概念 

继承是使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类

假如我们需要使用两个类,Student类和Teacher类,Student和Teacher都有姓名、电话、年龄这样的共同属性,但是有也有不同的部分,如:Student需要有学习函数study(),Teacher需要授课函数teaching() 。这两个类分别独立实现,有很多重复的代码,有没有办法不重复定义这些公共的部分,让代码变得简洁、高效?有,可以继承

class Student
{
public:
    //身份
    void identity()
    {
        cout << "void identity()" << _name << endl;
    }
    //学习
    void study()
    {
    }
protected:
    string _name = "name";  // 姓名
    string _address;  // 地址
    string _tel;  //电话号码
    int _age = 18;  //年龄
};

class Teacher
{
public:
    void identity()
    {
    }
    // 授课
    void teaching()
    {
    }
protected:
    string _name = "张三";  // 姓名
    int _age = 18;  // 年龄
    string _address;  // 地址
    string _tel;  //电话号码
    string _title;  //称号
};

使用继承: 

class Person
{
public:
    void identity()
    {
        cout << "void identity()" << _name << endl;
    }
protected:
    string _name = "张三";  //姓名
    string _address;//地址
    string _tel;  //电话
    int _age = 18;  //年龄
};
class Student : public Person
{
public:
    // 学习
    void study()
    {
    }
protected:
    int _stuid;//学号
};
class Teacher : public Person
{
public:
    //授课
    void teaching()
    {
    }
protected:
    string title;  //头衔
}; 

对于上面的代码,可以简单的理解为:定义了三个类,分别是Person类、Student类和Teacher类。关系上看,Student类与Teacher类都继承自Person类,称作派生类(子类)。内容上看,Student类和Teacher类公共的部分放在基类(父类),而c++定义子类中含有父类的属性和方法,同时,子类中自己还定义了额外的属性和方法,如上面的Student类当中定义了学号、学习函数,Teacher类定义了头衔、教学函数

 这样一来,与没有继承进行定义的类相比,Student类和Teacher类共同部分定义在了基类中,不同的部分就当独定义,使之前大量重复的代码不再重复,实现了代码复用

1.2继承的定义 

 1.2.1定义格式

有三种继承方式: 

三种访问方式:

1.2.2继承基类成员访问⽅式的变化 

类成员/继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected成员派生类的private成员
基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员

 而基类的private成员,无论被哪种方式继承,在子类中都是不可见的,这⾥的不可⻅是指基类的私有成员还是被继承到了派⽣类对象中,但是语法上限制派⽣类对象不管在类⾥⾯还是类外⾯都不能去访问它

如果基类成员不想在类外直接被访问,但需要在派⽣类中能访问,就定义为protected

对于上面表格的总结:基类的私有成员外,基类的其他成员 在派⽣类的访问⽅式==Min(成员在基类的访问限定符,继承⽅式),public >protected> private

  • 派生类可以用struct定义也可以用class定义,区别是:使⽤关键字class时默认的继承⽅式是private,使⽤struct时默认的继承⽅式是public,不过最好显⽰的写出继承⽅式
  • 在实际运⽤中⼀般使⽤都是public继承,⼏乎很少使⽤protetced/private继承,也不提倡使⽤ protetced/private继承,因为protetced/private继承下来的成员都只能在派⽣类的类⾥⾯使⽤,实 际中扩展维护性不强 

2.基类和派生类之间的转换 

  • public继承的派⽣类对象可以赋值给基类的指针/基类的引⽤。这⾥有个形象的说法叫切⽚或者切 割。寓意把派⽣类中基类那部分切出来,基类指针或引⽤指向的是派⽣类中切出来的基类那部分 
  • 基类对象不能赋值给派⽣类对象
  • 基类的指针或者引⽤可以通过强制类型转换赋值给派⽣类的指针或者引⽤。但是必须是基类的指针 是指向派⽣类对象时才是安全的

 

class Person
{
protected:
        string _name; // 姓名
        string _sex;  // 性别
        int _age;  // 年龄
};
class Student : public Person
{
public:
    int _No; // 学号
};
int main()
{
    Student sobj;
    // 1.派⽣类对象可以赋值给基类的指针/引⽤
    Person * pp = &sobj;
    Person& rp = sobj;
    
    // ⽣类对象可以赋值给基类的对象是通过调⽤后⾯会讲解的基类的拷⻉构造完成的
    Person pobj = sobj;

    //2.基类对象不能赋值给派⽣类对象,这⾥会编译报错
    sobj = pobj;
    return 0;
}

3.继承中的作用域 

3.1隐藏规则

  1. 在继承体系中基类和派⽣类都有独⽴的作⽤域
  2. 派⽣类和基类中有同名成员,派⽣类成员将屏蔽基类对同名成员的直接访问,这种情况叫隐藏。 (在派⽣类成员函数中,可以使⽤基类::基类成员显⽰访问)
  3. 需要注意的是如果是成员函数的隐藏只需要函数名相同就构成隐藏
  4. 注意在实际中在继承体系⾥⾯最好不要定义同名的成员

例如:

 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; // 学号

};

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

4.1常⻅默认成员函数 

  •  派⽣类的构造函数必须调⽤基类的构造函数初始化基类的那⼀部分成员。如果基类没有默认的构造 函数,则必须在派⽣类构造函数的初始化列表阶段显⽰调⽤
  • 派⽣类的拷⻉构造函数必须调⽤基类的拷⻉构造完成基类的拷⻉初始化
  • 派⽣类的operator=必须要调⽤基类的operator=完成基类的复制。需要注意的是派⽣类的 operator=隐藏了基类的operator=,所以显⽰调⽤基类的operator=,需要指定基类作⽤域
  • 派⽣类的析构函数会在被调⽤完成后⾃动调⽤基类的析构函数清理基类成员。因为这样才能保证派 ⽣类对象先清理派⽣类成员再清理基类成员的顺序
  • 派⽣类对象初始化先调⽤基类构造再调派⽣类构造
  • 派⽣类对象析构清理先调⽤派⽣类析构再调基类的析构
  • 因为多态中⼀些场景析构函数需要构成重写,重写的条件之⼀是函数名相同。那么编译器会对析构函数名进⾏特殊处理,处理成destructor(),所以基类析构函数不加 virtual的情况下,派⽣类析构函数和基类析构函数构成隐藏关系

5.与继承相关的要点 

  •  友元关系不能继承,也就是说基类友元不能访问派⽣类私有和保护成员
  • 基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。⽆论派⽣出多少个派⽣类,都只有⼀个static成员实例
  • c++支持多继承,意味着存在菱形继承,而菱形继承有数据冗余和⼆义性的问题,在有更好的解决方法时,千万不要使用菱形继承

 6.虚继承

很多⼈说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有 菱形虚拟继承,底层实现就很复杂,性能也会有⼀些损失,所以最好不要设计出菱形继承。多继承可 以认为是C++的缺陷之⼀,后来的⼀些编程语⾔都没有多继承,如Java 

class Person
{
public:string _name; // 姓名/*int _tel;int _age;string _gender;string _address; */// ...
};//使⽤虚继承Person类
class Student : virtual public Person
{
protected:int _num; //学号};// 使⽤虚继承Person类
class Teacher : virtual public Person
{
protected:int _id; // 职⼯编号};// 教授助理
class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修课程
};

我们可以设计出多继承,但是不建议设计出菱形继承,因为菱形虚拟继承以后,⽆论是使⽤还是底层 都会复杂很多。当然有多继承语法⽀持,就⼀定存在会设计出菱形继承,像Java是不⽀持多继承的, 就避开了菱形继承 

class Person
{
public:Person(const char* name):_name(name){}string _name; //姓名
};
class Student : virtual public Person
{
public:Student(const char* name, int num):Person(name), _num(num){}
protected:int _num; //学号
};
class Teacher : virtual public Person
{
public:Teacher(const char* name, int id):Person(name), _id(id){}
protected:int _id; //职⼯编号
};// 不建议玩菱形继承
class Assistant : public Student, public Teacher
{
public:Assistant(const char* name1, const char* name2, const char* name3):Person(name3),Student(name1, 1),Teacher(name2, 2){}
protected:string _majorCourse; // 主修课程
};
int main()
{// 思考⼀下这⾥a对象中_name是"张三", "李四", "王五"中的哪⼀个?Assistant a("张三", "李四", "王五");return 0;
}

 

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

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

相关文章

3dtiles平移旋转工具制作

3dtiles平移旋转缩放原理及可视化工具实现 背景 平时工作中&#xff0c;通过cesium平台来搭建一个演示场景是很常见的事情。一般来说&#xff0c;演示场景不需要多完善的功能&#xff0c;但是需要一批三维模型搭建&#xff0c;如厂房、电力设备、园区等。在实际搭建过程中&…

我是如何从 0 到 1 找到 Web3 工作的?

作者&#xff1a;Lotus的人生实验 关于我花了一个月的时间&#xff0c;从 0 到 1 学习 Web3 相关的知识和编程知识。然后找到了一个 Web3 创业公司实习的远程工作。 &#x1f447;&#x1f447;&#x1f447; 我的背景: 计算机科班&#xff0c;学历还可以(大厂门槛水平) 毕业工…

进程状态(R|S|D|t|T|X|Z)、僵尸进程及孤儿进程

文章目录 一.进程状态进程排队状态&#xff1a;运行、阻塞、挂起 二.Linux下的进程状态R 运行状态&#xff08;running&#xff09;S 睡眠状态&#xff08;sleeping)D 磁盘休眠状态&#xff08;Disk sleep&#xff09;t 停止、暂停状态(tracing stopped)T 停止、暂停状态(stopp…

为什么要将PDF转换为CSV?CSV是Excel吗?

在企业和数据管理的日常工作中&#xff0c;PDF文件和CSV文件承担着各自的任务。PDF通常用于传输和展示静态的文档&#xff0c;而CSV因其简洁、易操作的特性&#xff0c;广泛应用于数据存储和交换。如果需要从PDF中提取、分析或处理数据&#xff0c;转换为CSV格式可能是一个高效…

Starlink卫星动力学系统仿真建模第十讲-基于SMC和四元数的卫星姿态控制示例及Python实现

基于四元数与滑模控制的卫星姿态控制 一、基本原理 1. 四元数姿态表示 四元数运动学方程&#xff1a; 3. 滑模控制设计 二、代码实现&#xff08;Python&#xff09; 1. 四元数运算工具 import numpy as npdef quat_mult(q1, q2):"""四元数乘法""…

CSS—引入方式、选择器、复合选择器、文字控制属性、CSS特性

目录 CSS 1.引入方式 2.选择器 3.复合选择器 4.文字控制属性 5.CSS特性 CSS 层叠样式表&#xff0c;是一种样式表语言&#xff0c;用来描述HTML文档的呈现 书写时一般按照顺序&#xff1a;盒子模型属性—>文字样式—>圆角、阴影等修饰属性 1.引入方式 引入方式方…

OpenHarmony-4.基于dayu800 GPIO 实践(2)

基于dayu800 GPIO 进行开发 1.DAYU800开发板硬件接口 LicheePi 4A 板载 2x10pin 插针&#xff0c;其中有 16 个原生 IO&#xff0c;包括 6 个普通 IO&#xff0c;3 对串口&#xff0c;一个 SPI。TH1520 SOC 具有4个GPIO bank&#xff0c;每个bank最大有32个IO&#xff1a;  …

win11 24h2 远程桌面 频繁断开 已失去连接 2025

一、现象 Windows11自升级2025年2月补丁后版本号为系统版本是26100.3194&#xff0c;远程桌面频繁断开连接&#xff0c;尝试连接&#xff0c;尤其在连接旧的server2012 二、临时解决方案 目前经测试&#xff0c;在组策略中&#xff0c;远程桌面连接客户端&#xff0c;关闭客户…

rust学习笔记6-数组练习704. 二分查找

上次说到rust所有权看看它和其他语言比有什么优势&#xff0c;就以python为例 # Python3 def test():a [1, 3, -4, 7, 9]print(a[4])b a # 所有权没有发生转移del b[4]print(a[4]) # 由于b做了删除&#xff0c;导致a再度访问报数组越界if __name__ __main__:test() 运行结…

Windows安装NVIDIA显卡CUDAD调用GPU,适用于部署deepseek r1

显卡、显卡驱动、CUDA之间的关系 显卡&#xff1a;&#xff08;GPU&#xff09;&#xff0c;主流是NVIDIA的GPU&#xff0c;因为深度学习本身需要大量计算。GPU的并行计算能力&#xff0c;在过去几年里恰当地满足了深度学习的需求。AMD的GPU基本没有什么支持&#xff0c;可以不…

基于无人机遥感的烟株提取和计数研究

一.研究的背景、目的和意义 1.研究背景及意义 烟草作为我国重要的经济作物之一&#xff0c;其种植面积和产量的准确统计对于烟草产业的发展和管理至关重要。传统的人工烟株计数方法存在效率低、误差大、难以覆盖大面积烟田等问题&#xff0c;已无法满足现代烟草种植管理的需求…

《深度学习实战》第3集:循环神经网络(RNN)与序列建模

第3集&#xff1a;循环神经网络&#xff08;RNN&#xff09;与序列建模 引言 在深度学习领域&#xff0c;处理序列数据&#xff08;如文本、语音、时间序列等&#xff09;是一个重要的研究方向。传统的全连接网络和卷积神经网络&#xff08;CNN&#xff09;难以直接捕捉序列中…

【前沿探索篇七】【DeepSeek自动驾驶:端到端决策网络】

第一章 自动驾驶的"感官革命":多模态神经交响乐团 1.1 传感器矩阵的量子纠缠 我们把8路摄像头+4D毫米波雷达+128线激光雷达的融合称为"传感器交响乐",其数据融合公式可以简化为: def sensor_fusion(cam, radar, lidar):# 像素级特征提取 (ResNet-152…

可狱可囚的爬虫系列课程 13:Requests使用代理IP

一、什么是代理 IP 代理 IP&#xff08;Proxy IP&#xff09;是一个充当“中间人”的服务器IP地址&#xff0c;用于代替用户设备&#xff08;如电脑、手机等&#xff09;直接与目标网站或服务通信。用户通过代理IP访问互联网时&#xff0c;目标网站看到的是代理服务器的IP地址&…

https:原理

目录 1.数据的加密 1.1对称加密 1.2非对称加密 2.数据指纹 2.1数据指纹实际的应用 3.数据加密的方式 3.1只使用对称加密 3.2只使用非对称加密 3.3双方都使用对称加密 3.4非对称加密和对称加密一起使用 4.中间人攻击 5.CA证书 5.1什么是CA证书 CA证书的验证 6.https的原理 1.数据…

Github项目管理之 其余分支同步main分支

文章目录 方法&#xff1a;通过 Pull Request 同步分支1. **创建一个从 main 到目标分支的 Pull Request**2. **合并 Pull Request** 注意事项总结 在 GitHub 网页上&#xff0c;你可以通过 Pull Request 的方式将一个分支&#xff08;例如 main 分支&#xff09;的修改同步到…

Aseprite绘画流程案例(5)——花盆

1.最终图片效果 参考素材来源于&#xff1a;手绘像素画第三课&#xff1a;像素画盆花示范&#xff08;无参考图&#xff09;_哔哩哔哩_bilibili 2.流程 1.新建画布40X27的画布&#xff0c;打开显示网格&#xff0c;背景色为白色 2.画出梯形的盆 3.给盆进行亮暗对比上色 4.添…

【模板】csdn markdown语法演示

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

【Python系列】PYTHONUNBUFFERED=1的作用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Adobe After Effects的动画制作

作者&#xff1a;余佳琪 目录 一、 前言 二、 可动骨骼的选择 三、 运动曲线的设置 四、 图层的选定与应用 五、 插件的应用&#xff08;阴影&#xff0c;高光&#xff0c;特效&#xff09; 六、 导出 一、 前言 在当今世界&#x…