继承详细总结

一.继承的定义与概念

1.定义:继承是一种is-a的关系,例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。

2.允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数) 和 属性(成员变量),这样产生新的类,称派生类

3.定义格式:

例:基类(也称父类) Person

class Person {
public:void Print() {cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "peter";  // 姓名int _age = 18;  // 年龄
};

从这个基类派生出 Student 类(也称子类)

class Student : public Person {
protected:int _stuid;  // 学号
};

3.访问限定 

不同的访问限定符决定了基类成员在派生类中的可见性和访问权限。以 public 继承为例,基类的 public 成员在派生类中依然是 public,基类的 protected 成员在派生类中仍是 protected,而基类的 private 成员在派生类中不可见。

4.继承方式

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

派生类对象可以赋值给基类的对象、指针或引用,这一过程形象地称为 “切片” 或 “切割”。

将基类对象赋值给派生类对象是不被允许的因为基类对象可能缺少派生类特有的成员。

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 = &sobj;Student* ps1 = (Student*)pp;  // 这种情况转换时可以的,因为 pp 原本就指向 Student 对象ps1->_No = 10;pp = &pobj;Student* ps2 = (Student*)pp;  // 这种情况转换时虽然可以,但会存在越界访问的问题,因为 pp 指向的是 Person 对象,不是 Student 对象ps2->_No = 10;  // 可能会引发运行时错误
}

三.继承中的作用域 

当子类和父类存在同名成员时,子类成员会屏蔽父类对同名成员的直接访问,这种现象称为隐藏或重定义

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;  // 学号,与 Person 类中的 _num 同名
};void Test() {Student s1;s1.Print();
}

在 Student 类的 Print 函数中,如果直接访问 _num,则访问的是 Student 类自身的 _num(学号)。若要访问基类 Person 的 _num(身份证号),需要使用 Person::_num 的方式进行显示访问

此外,对于成员函数的隐藏,只要函数名相同就会构成隐藏,即使函数参数列表不同。例如:

class A {
public:void fun() {cout << "func()" << endl;}
};class B : public A {
public:void fun(int i) {A::fun();  // 调用基类的 fun 函数cout << "func(int i)->" << i << endl;}
};void Test() {B b;b.fun(10);
}

在 B 类中定义了 fun(int i) 函数,它隐藏了基类 A 中的 fun 函数。在 B 类的 fun(int i) 函数中,可以通过 A::fun() 来调用基类的 fun 函数

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

派生类的构造函数必须调用基类的构造函数来初始化基类部分的成员。如果基类没有默认构造函数,则必须在派生类构造函数的初始化列表中显式调用

class Person {
public:Person(const char* name = "peter"): _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): 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) {cout << "Student& operator=(const Student& s)" << endl;if (this!= &s) {Person::operator=(s);  // 调用基类赋值运算符函数初始化基类成员_num = s._num;}return *this;}~Student() {cout << "~Student()" << endl;}
protected:int _num;  // 学号
};void Test() {Student s1("jack", 18);Student s2(s1);Student s3("rose", 17);s1 = s3;
}

注意:

    Student(const char* name, int num): Person(name), _num(num) {  // 调用基类构造函数初始化基类成员cout << "Student()" << endl;}

在初始化成员列表中,先调用了基类的构造函数,然后对派生类的成员进行初始化

构造函数与析构函数的顺序 

 五.继承与友元

友元关系不能继承。这意味着基类的友元函数不能访问派生类的私有和保护成员

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);
}

Display 函数是 Person 类的友元函数,它可以访问 Person 类的私有成员 _name,但不能访问 Student 类的私有成员 _stuNum,即使 Student 类继承自 Person 类。

六.继承与静态成员

当基类定义了静态成员时,整个继承体系中只有一个该静态成员的实例。无论派生出多少个子类,它们都共享这一静态成员

class Person {
public:Person() { ++_count; }
protected:string _name;  // 姓名
public:static int _count;  // 统计人的个数
};int Person::_count = 0;class Student : public Person {
protected:int _stuNum;  // 学号
};class Graduate : public Student {
protected:string _seminarCourse;  // 研究科目
};void TestPerson() {Student s1;Student s2;Student s3;Graduate s4;cout << "人数 :" << Person::_count << endl;  // 输出 4,因为共创建了 4 个 Person 或其派生类对象Student::_count = 0;  // 可以通过派生类名访问静态成员,但实际上修改的是基类的静态成员cout << "人数 :" << Person::_count << endl;  // 输出 0
}

Person 类的静态成员 _count 用于统计创建的 Person 及其派生类对象的数量。无论是通过 Person 类还是 Student 类来访问 _count,都是同一个静态成员变量。

 

参考了这位大佬的文章,并结合自己的情况进行了总结

A charmer-CSDN博客A charmer擅长C++,数据结构,算法,等方面的知识,A charmer关注c++,c语言,linux,数据结构领域.https://charmer.blog.csdn.net/

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

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

相关文章

批量多线程给TXT文档插入相关腾讯AI【高质量无水印无版权】原创图片

给蜘蛛访问的网站文章插入相关图片&#xff0c;可以带来以下好处&#xff1a; ‌1、提升用户体验‌&#xff1a;图片能够直观地展示文章内容&#xff0c;帮助用户更好地理解和消化信息。对于阅读者来说&#xff0c;图文并茂的内容往往更具吸引力&#xff0c;也能提高他们的阅读…

牵手红娘:牵手App红娘助力“牵手”,脱单精准更便捷

随着互联网的普及&#xff0c;现代青年的社交圈层加速扩大&#xff0c;他们的恋爱观也正经历着前所未有的转变。在繁忙的工作之余&#xff0c;人们希望能够找到一种既高效又真诚的交友方式。于是&#xff0c;线上交友平台成为了他们寻找爱情的新选择。让不同文化背景、不同工作…

STM32-笔记12-实现SysTick模拟多线程流水灯

1、前言 正常STM32实现多线程&#xff0c;需要移植一个操作系统FreeRTOS。但是在这里不移植FreeRTOS怎么实现多线程呢&#xff1f;使用SysTick&#xff0c;那么怎么使用SysTick来模拟多线程呢&#xff1f;前面我们知道SysTick就是一个定时器&#xff0c;它不是在主函数的while循…

麒麟信安受邀出席开放原子园区行暨供需对接活动,分享基于关基领域打造的行业解决方案

12月17日&#xff0c;武汉市经信局和开放原子开源基金会共同主办开放原子园区行暨供需对接活动&#xff0c;旨在推进武汉市开源体系建设&#xff0c;推动开源技术赋能千行百业。活动吸引了武汉市委金融办、市卫健委、疾控中心、医保局、信息中心(大数据中心)、市红十字会、银行…

golang 并发--goroutine(四)

golang 语言最大的特点之一就是语法上支持并发&#xff0c;通过简单的语法很容易就能创建一个 go 程&#xff0c;这就使得 golang 天生适合写高并发的程序。这一章节我们就主要介绍 go 程&#xff0c;但是要想完全理解 go 程我们需要深入研究 GPM 模型&#xff0c;关于 GPM 模型…

SpringAI人工智能开发框架006---SpringAI多模态接口_编程测试springai多模态接口支持

可以看到springai对多模态的支持. 同样去创建一个项目 也是跟之前的项目一样,修改版本1.0.0 这里 然后修改仓库地址,为springai的地址 然后开始写代码

JSON 系列之1:将 JSON 数据存储在 Oracle 数据库中

本文为Oracle数据库JSON学习系列的第一篇&#xff0c;讲述如何将JSON文档存储到数据库中&#xff0c;包括了版本为19c和23ai的情形。 19c中的JSON 先来看一下数据库版本为19c时的情形。 创建表colortab&#xff0c;其中color列的长度设为4000。若color的长度需要设为32767&a…

SOME/IP 协议详解——信息格式

文章目录 1. 头部格式1.1 消息 ID&#xff08;Message ID&#xff09;1.2 长度&#xff08;Length&#xff09;1.3 请求 ID&#xff08;Request ID&#xff09;1.4 协议版本&#xff08;Protocol Version&#xff09;&#xff1a;1.5 接口版本&#xff08;Interface Version&am…

Spring学习(一)——Sping-XML

一、Spring的概述 (一)什么是Spring? Spring是针对bean对象的生命周期进行管理的轻量级容器。提供了功能强大IOC、AOP及Web MVC等功能。Spring框架主要由七部分组成&#xff1a;分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 S…

用 gdbserver 调试 arm-linux 上的 AWTK 应用程序

很多嵌入式 linux 开发者都能熟练的使用 gdb/lldb 调试应用程序&#xff0c;但是还有不少朋友在调试开发板上的程序时&#xff0c;仍然在使用原始的 printf。本文介绍一下使用 gdbserver 通过网络调试开发板上的 AWTK 应用程序的方法&#xff0c;供有需要的朋友参考。 1. 下载 …

树莓派换源

查询自己版本&#xff1a; lsb_release -a bullseye可以理解为树莓派的系统代号&#xff08;10&#xff0c;11&#xff0c;12都不同&#xff0c;一定要看好自己系统是什么版本&#xff09; 查询架构 uname -a aarch64的地方就是代表系统架构的&#xff0c;我的是aarch64的架…

MySQL索引-索引的结构和原理

索引原理 查找算法 顺序查找 数组链表 二分查找 B树跳表 散列查找 Hash表 DFS 树图 BFS 树图 分块查找 海量数据 Hash结构 Hash索引可以方便的提供等值查询&#xff0c;但是对于范围查询就需要全表扫描了。 Hash索引在MySQL 中Hash结构主要应用在InnoDB 自适应哈希索引。…

【Linux探索学习】第二十三弹——理解文件系统:认识硬件、探索文件在硬件上的存储问题

Linux学习笔记&#xff1a;https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 我们前面讲过了文件的组成是由文件内容和文件属性两者组成的&#xff0c;但是我们前面接触的文件都是系统中的文件&#xff0c;都是已经在进…

深度学习中的并行策略概述:2 Data Parallelism

深度学习中的并行策略概述&#xff1a;2 Data Parallelism 数据并行&#xff08;Data Parallelism&#xff09;的核心在于将模型的数据处理过程并行化。具体来说&#xff0c;面对大规模数据批次时&#xff0c;将其拆分为较小的子批次&#xff0c;并在多个计算设备上同时进行处…

分布式专题(10)之ShardingSphere分库分表实战指南

一、ShardingSphere产品介绍 Apache ShardingSphere 是一款分布式的数据库生态系统&#xff0c; 可以将任意数据库转换为分布式数据库&#xff0c;并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。Apache ShardingSphere 设计哲学为 Database Plus&#xff0c;旨在…

帧缓存的分配

帧缓存实际上就是一块内存。在 Android 系统中分配与回收帧缓存&#xff0c;使用的是一个叫 ION 的内核模块&#xff0c;App 使用 ioctl 系统调用后&#xff0c;会在内核内存中分配一块符合要求的内存&#xff0c;用户态会拿到一个 fd&#xff08;有的地方也称之为 handle&…

vue3+vite一个IP对站点名称的前端curd更新-会议系统优化

vue3-tailwind-todo https://github.com/kgrg/vue3-tailwind-todo 基于这个项目,把ip到sta的映射做了前端管理. 核心代码是存储和获得的接口,需要flask提供. def redis2ipdic():global ipdicipdic.clear()tmdiccl.hgetall(IPDIC_KEY)for k in tmdic.keys():ipdic[k.decode() …

Elasticsearch-脚本查询

脚本查询 概念 Scripting是Elasticsearch支持的一种专门用于复杂场景下支持自定义编程的强大的脚本功能&#xff0c;ES支持多种脚本语言&#xff0c;如painless&#xff0c;其语法类似于Java,也有注释、关键字、类型、变量、函数等&#xff0c;其就要相对于其他脚本高出几倍的性…

golang LeetCode 热题 100(动态规划)-更新中

爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a;输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2&…

【每日学点鸿蒙知识】Charles抓包、lock文件处理、WebView组件、NFC相关、CallMethod失败等

1、HarmonyOS系统中如何使用Charles抓包&#xff1f; 在HarmonyOS操作系统中&#xff0c;使用Charles进行抓包的步骤如下&#xff1a; 在Charles中设置代理。 首先&#xff0c;在Charles的菜单栏上选择“Proxy”→“Proxy Settings”&#xff0c;然后填入代理端口&#xff0…