c++的三大特性之关于继承

目录

继承的概念及定义

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

继承中的作用域

派生类的默认成员函数

继承与友元,静态成员


继承的概念及定义

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

示例:

class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}protected:string _name = "Andy"; // 姓名int _age = 18;  // 年龄
};// 继承后父类Person的成员(成员函数+成员变量)都会变成子类的一部分。
class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};

定义:Person是父类,也称作基类。Student是子类,也称作派生类

继承关系和访问限定符

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

总结:
  • 1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它

  • 2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的

  • 3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected> private。

  • 4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式

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

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

        1.派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫 切片或者切割 。寓意把派生类中父类那部分切来赋值过去。
        2.基类对象不能赋值给派生类对象。
        3.基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(RunTime Type Information)的dynamic_cast 来进行识别后进行安全转换。

class Person
{
protected :string _name; // 姓名string _sex;  // 性别int _age; // 年龄
};class Student : public Person
{
public :int _No ; // 学号
};void Test ()
{Student sobj ;// 1.子类对象可以赋值给父类对象/指针/引用Person pobj = sobj ;Person* pp = &sobj;Person& rp = sobj;//2.基类对象不能赋值给派生类对象sobj = pobj;// 3.基类的指针可以通过强制类型转换赋值给派生类的指针pp = &sobjStudent* ps1 = (Student*)pp; // 这种情况转换时可以的。ps1->_No = 10;
}
注意:在公有继承下,子类赋值给基类是天然支持的,不存在隐式类型转换

继承中的作用域

1. 在继承体系中 基类 派生类 都有 独立的作用域
2. 子类和父类中有同名成员, 子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏, 也叫重定义。 (在子类成员函数中,可以 使用基类 :: 基类成员显示访问

3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
4. 注意在实际中在 继承体系里 面最好 不要定义同名的成员

派生类的默认成员函数(很重要,画圈圈)

“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?
  • 1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

  • 2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。

  • 3. 派生类的operator=必须要调用基类的operator=完成基类的复制。

  • 4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。

  • 5. 派生类对象初始化先调用基类构造再调派生类构造。

  • 6. 派生类对象析构清理先调用派生类析构再调基类的析构

  • 7. 因为一些场景析构函数需要构成重写,重写的条件之一是函数名相同。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。

    

class Person
{
public:Person(const char* name = "Andy"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person & p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num)//:_name(name)  error:Person(name) //需要显示调用,_num(num){cout << "Student()" << endl;}//这里调用父类的拷贝构造需要传过去一个父类对象//那么如何拿到一个父类的对象呢? ---  切片Student(const Student& s):Person(s),_num(s._num){cout << "Student(const Student& s)" << endl;}Student operator=(const Student& s){if (this != &s){//operator=(s); //这里构成隐藏Person::operator=(s);_num = s._num;}cout << "Student operator=(const Student& s)" << endl;return *this;}//由于多态的原因,析构函数会被处理成destructor//destructor(){}~Student()  //{//Person::~Person();  //这里构成隐藏cout << "~Student()" << endl;}//注:子类的析构函数完成时,会自动调用父类析构,保障先析构子,在析构父protected:int _num; //学号
};int main()
{Student s("Andy",18);//Student s1(s);//Person p = s;//s = s1;return 0;
}

继承与友元,静态成员

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
class Student;
class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name; // 姓名
};class Student : public Person
{
protected:int _stuNum; // 学号
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl;
}void main()
{Person p;Student s;Display(p, s);
}

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。
class Person
{
public:Person() { ++_count; }
public:string _name; // 姓名public:static int _count; // 统计人的个数。
};
int Person::_count = 0;class Student : public Person
{
protected:int _stuNum; // 学号
};class Graduate : public Student
{
protected:string _seminarCourse; // 研究科目
};int main()
{Person p1;Student s1;cout << &p1._name << endl;cout << &s1._name << endl;cout << &p1._count << endl;cout << &s1._count << endl;Graduate g1;Graduate g2;cout << Person::_count << endl;cout << Graduate::_count << endl;//父类静态成员子类共享return 0;
}


以上仅供参考,欢迎讨论

 

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

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

相关文章

gitee创建仓库

描述 本文章记录了怎么在gitee上创建项目&#xff0c;以及使用vscode提代码到远程呢个仓库&#xff0c;如何创建一个新分支&#xff0c;并将新分支提交到远程仓库。 1、创建远程仓库 在创建远程仓库之前要先进行ssh密钥的设置 &#xff08;1&#xff09;打开黑窗口&#xff…

iptables 防火墙(二)

目录 1. SNAT 策略及应用 1.1 SNAT策略概述 1. 只开启路由转发&#xff0c;未设置地址转换的情况 2. 开启路由转发&#xff0c;并设置SNAT转换的情况 1.2 SNAT策略的应用 1. 2.1 共享固定IP上网 &#xff08;1&#xff09;打开网关的路由转发 &#xff08;2&#xff09;…

[C#]C# OpenVINO部署yolov8目标检测模型

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 YOLOv8 抛弃了前几代模型的 Anchor-Base。 YOLO 是一种基于图像全局信息进行预测的目标检测系统。自 2015 年 Joseph Redmon、Ali Farhadi 等人提出初代模型以来&#xff0c;领域内的研究者们…

大数据Doris(四十九):Doris数据导出介绍

文章目录 Doris数据导出介绍 一、​​​​​​​使用示例

静态网页设计——个人简介网站

前言 使用经典前端三件套HTMLCSSJavascript编写了一个关于个人简介的静态网页&#xff0c;可以根据自己的需要&#xff0c;十分简单的进行修改。 首页 首页由上方的菜单栏以及菜单栏下面的轮播图组成&#xff0c;再往下走&#xff0c;是关于自己的兴趣爱好的部分&#xff0c…

django学习:页面渲染与请求和响应

1.请求过程 2.页面渲染 在app中新建一个目录&#xff08;Directory&#xff09;&#xff0c;文件名命名为templates。该文件名命名是固定的&#xff0c;不可命名出错&#xff0c;如若后续步骤出错&#xff0c;该目录文件名是一个检查的重点项目。在该目录下新建一个html文件&a…

深度学习:大规模模型分布式训练框架DeepSpeed

深度学习&#xff1a;大规模模型分布式训练框架DeepSpeed DeepSpeed简介DeepSpeed核心特点DeepSpeed如何工作&#xff1f;DeepSpeed如何使用&#xff1f;参考文献 DeepSpeed简介 随着机器学习模型变得越来越复杂和庞大&#xff0c;训练这些模型所需的计算资源也在不断增加。特别…

如何查找iPhone中所有的应用程序

​ ​ Apple 的 App Store 共有约 200 万个适用于 iPhone 和 iPad 的应用程序。如果您像我们一样&#xff0c;您的 iOS 或 iPadOS 设备上可能有数十个应用程序&#xff0c;但没有机会将它们全部整理好。您很容易忘记主屏幕上应用程序图标的位置。 幸运的是&#xff0c;iPhone…

向日葵远程工具的使用Mysql5.7的安装与配置

目录 一、向日葵远程安装与使用 二、Mysql 5.7 安装与配置 2.1 安装 2.2 Navicat Premium 12 测试连接 本机测试连接 外部访问MySQL测试连接 三、思维导图 一、向日葵远程安装与使用 简介&#xff1a; 向日葵远程控制是一款用于对远程PC进行管理和服务的软件,拥有5秒快速…

智能型参数可设置比例阀放大器

智能型参数可设置比例阀放大器是一种电液控制技术&#xff0c;它可以驱动不带电气位移反馈的各种比例溢流阀、比例流量阀、比例减压阀、比例方向阀和比例插装阀等。 这种放大器的特点是可以将输入的模拟量指令信号进行处理运算&#xff0c;通过比例电磁铁将驱动电流线性转换为作…

网页爬虫对于网络安全有哪些影响?

在当今信息爆炸的时代&#xff0c;网络已经成为人们获取信息、交流思想和开展业务的重要平台。然而&#xff0c;随着网络的普及和技术的不断发展&#xff0c;网络安全问题也日益凸显&#xff0c;其中网页爬虫对网络安全的影响不容忽视。本文将就网页爬虫对网络安全的影响进行深…

PyQt 多线程多进程研究

杰哥&#xff0c;PyQT系统界面卡顿的问题是因为检测图片的耗时太长了&#xff0c;大概一张图片四十多秒。如果用多线程来解决耗时几秒的任务&#xff0c;是可以在之前卡顿问题上进一步解决的。但是不能解决像我们这种超长耗时的任务的&#xff0c;只能利用多线程来避免。我尝试…

Transformer从菜鸟到新手(二)

引言 这是Transformer的第二篇文章&#xff0c;上篇文章中我们了解了分词算法BPE&#xff0c;本文我们继续了解Transformer中的位置编码和核心模块——多头注意力。 位置编码 我们首先根据BPE算法得到文本切分后的子词标记&#xff0c;然后经过输入嵌入层将每个标记转换为对…

FreeRTOS——互斥信号量知识总结及其实战

1互斥信号量的概念 1&#xff09;互斥信号量&#xff1a;是一个拥有优先级继承的二值信号量&#xff0c;在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中&#xff01; 2&#xff09;优先级继承&#xff1a;当一个互斥信号量正在被一个低优先级的…

DIY 云成本优化的5大挑战

外星人。 黑暗骑士。 帝国反击战。 在 Incredibuild&#xff0c;如果有一样东西我们喜欢&#xff0c;那就是我们的话题永远有续集。我们将针对云端优化推出一个更深入的续集&#xff0c; 但这一次我们谈论的是云成本优化&#xff0c;采用 DIY 的方式。&#xff08;如果你还不…

k8s pod基础 1

发布和yaml文件的初步了解。 pod&#xff1a;是k8s中最小的资源管理组件。 pod也是最小化运行容器化的应用的资源管理对象。 pod是一个抽象的概念&#xff0c;可以理解为一个或者多个容器化应用的集合。 在一个pod当中运行一个容器是最常用的方式。 在一个pod当中可以同时…

云计算:OpenStack 分布式架构管理FLAT网络(单控制节点与多计算节点)

目录 一、实验 1.环境 2.控制节点创建网络 3.控制节点创建规格 4.控制节点新增安全组入口规则 5.控制节点创建实例 二、问题 1.FLAT网络底层如何实现 2.无法SSH 云主机实例 一、实验 1.环境 (1) 主机 表1 主机 主机架构IP备注controller控制节点192.168.204.210已部…

Swift并发的结构化编程

并发&#xff08;concurrency&#xff09; 早期的计算机 CPU 都是单核的&#xff0c;操作系统为了达到同时完成多个任务的效果&#xff0c;会将 CPU 的执行时间分片&#xff0c;多个任务在同一个 CPU 核上按时间先后交替执行。由于 CPU 执行速度足够地快&#xff0c;给人的错觉…

【单片机 TB作品】节拍器,电子音乐节拍器,51单片机,Proteus仿真

节拍器的使用可以使练琴者正确掌握乐曲的速度,从而使音 乐练习达到事半功倍的效果。本课题基于单片机设计具有声光晋 示的电子乐器节拍器,充分利用单片机的定时和中断系统,通过 C语言程序设计,控制外部相关硬件电路,实现对音乐速,度 40~120次/分钟范围内连续可调,节拍114、 2/4…

【Electron】快速建立Vue3+Vite+Electron Ts项目

git https://github.com/electron-vite/electron-vite-vue 创建项目 npm create electron-vite or pnpm create electron-vite 初始化 pnpm install or pnpm i 启动项目 pnpm dev 打包项目 pnpm build 项目创建成功后默认情况下 窗口是H800 W600 在createWindow 函数…