C++-带你初步走进继承(1)

1.继承的概念及定义

1.1继承的概念

继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段,它允许程序员在
持原有类特性的基础上进行扩展 ,增加功能,这样产生新的类,称派生类。继承 呈现了面向对象
程序设计的层次结构 ,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,
承是类设计层次的复用。
大家都知道c++的三大特性就是:面向对象,继承,多态。那么继承最重要的特点就是代码的复用。接下来我来带大家了解一下继承的概念。
下面我写了三个类,Student类和Teacher类都继承了Person类,当我们调用监视窗口可以看到,Person类里面的成员变量和成员函数在Student类和Teacher类中都有,并且Student类和Teacher类还多了自己的成员变量。
class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "xxx";int _age = 18;
};class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};int main()
{Student s;s.Print();Teacher t;t.Print();return 0;
}

1.2 继承定义

1.2.1定义格式

下面我们看到 Person 是父类,也称作基类。 Teacher是子类,也称作派生类。 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。

1.2.2继承关系和访问限定符

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

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

当我把Student变成保护继承之后,就会发生报错,因为Print就变成了保护函数,访问不了变量。 

 

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

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用 。这里有个形象的说法叫切片
或者切割。寓意把派生类中父类那部分切来赋值过去。
基类对象不能赋值给派生类对象。

3.继承中的作用域

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

我在Person类和Student类都写了一个fun函数,这两个fun函数只有参数不同,那么是构成重载吗?不是,这两个函数构成隐藏 ,为什么呢?因为两个类的作用域是独立的,而构成重载的前提是同一作用域。

 

 

如果出现基类和派生类定义了同名成员,可以使用使用 基类::基类成员 显示访问。


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

6 个默认成员函数, 默认 的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类
中,这几个成员函数是如何生成的呢?
1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
3. 派生类的 operator= 必须要调用基类的 operator= 完成基类的复制。
4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
保证派生类对象先清理派生类成员再清理基类成员的顺序。
5. 派生类对象初始化先调用基类构造再调派生类构造。
6. 派生类对象析构清理先调用派生类析构再调基类的析构。
7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同 ( 这个我们后面会讲
) 。那么编译器会对析构函数名进行特殊处理,处理成 destrutor() ,所以父类析构函数不加
virtual 的情况下,子类析构函数和父类析构函数构成隐藏关系。
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:protected:int _id;//学号
};int main()
{Student s;return 0;
}

当我实例化一个Student的对象s时,调用了父类的构造和析构函数,这就说明了当派生类进行实例化时,会调用基类的构造函数来构造派生类中基类的成员。

 当我自己写了一个Student的构造函数,那么怎么初始化基类的成员呢?可以在初始化列表调用基类的构造函数,然后我们可以看到,是先调用了基类的构造函数,再构造派生类的成员。

那么拷贝构造和赋值重载怎么构造的呢?也是差不多的,使用基类的构造函数完成对基类成员的构造,然后使用赋值的切片,把基类的成员切过去构造。

 

那析构函数呢?析构函数需要显示调用,而且还有一个特殊处理,就是析构要先析构派生类再析构基类。因为先析构基类的话,万一派生类使用了基类的成员,而且基类已经被析构,有可能出现基类资源已经清理释放掉了,然后派生类还去访问了基类的成员,就会存在野指针的问题。所以在派生类的析构函数被调用之后,基类的析构函数会自动调用。

 

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 id):_id(id),Person(name){cout << "Student()" << endl;}Student(const Student& s):Person(s),_id(s._id){cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){cout << "Student& operator=(const Student& s)" << endl;if (this != &s){_id = s._id;Person::operator=(s);}return *this;}~Student(){//Person::~Person();cout << "~Student()" << endl;}
protected:int _id;//学号
};int main()
{Student s1("张三",18);Student s2(s1);Student s3 = s1;return 0;
}

今天的分享到这里就结束了,感谢大家的阅读!

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

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

相关文章

如何在IDEA中使用固定公网地址SSH远程连接服务器开发环境

文章目录 1. 检查Linux SSH服务2. 本地连接测试3. Linux 安装Cpolar4. 创建远程连接公网地址5. 公网远程连接测试6. 固定连接公网地址7. 固定地址连接测试 本文主要介绍如何在IDEA中设置远程连接服务器开发环境&#xff0c;并结合Cpolar内网穿透工具实现无公网远程连接&#xf…

Compose 1.6 发布:性能大升级、拖放新功能、文本新变化...

翻译自&#xff1a; https://android-developers.googleblog.com/2024/01/whats-new-in-jetpack-compose-january-24-release.html 基于 1 月 24 号的 Compose 发行计划&#xff0c;我们正式推出了 Jetpack Compose 1.6 版本。 作为 Android 平台备受推崇的原生 UI 工具包&…

P4447 [AHOI2018初中组] 分组题解

题目 小可可的学校信息组总共有n个队员&#xff0c;每个人都有一个实力值。现在&#xff0c;一年一度的编程大赛就要到了&#xff0c;小可可的学校获得了若干个参赛名额&#xff0c;教练决定把学校信息组的n个队员分成若干个小组去参加这场比赛。 但是每个队员都不会愿意与实…

安全测试工具安装指南:在统信UOS上部署Burp Suite

原文链接&#xff1a;安全测试工具安装指南&#xff1a;在统信UOS上部署Burp Suite 大家好&#xff01;在网络安全领域&#xff0c;Burp Suite是一款不可或缺的工具&#xff0c;它提供了从初级映射和分析应用程序攻击面到查找和利用安全漏洞的一系列功能。今天&#xff0c;我将…

Shiro-05-shiro 基础知识补充密码学+哈希散列

密码学 密码术是隐藏或混淆数据的过程&#xff0c;因此窥探眼睛无法理解它。 Shiro的加密目标是简化JDK的加密支持并使之可用。 需要特别注意的是&#xff0c;密码通常不是特定于主题的&#xff0c;因此Shiro API的其中一个领域不是特定于主题的。 即使未使用“主题”&…

【elk查日志 elastic(kibana)】

文章目录 概要具体的使用方式一&#xff1a;查找接口调用历史二&#xff1a;查找自己的打印日志三&#xff1a;查找错误日志 概要 每次查日志&#xff0c;我都需要别人帮我&#xff0c;时间长了总觉得不好意思&#xff0c;所以这次下定决心好好的梳理一下&#xff0c;怎么查日…

spellman电源维修X3635系列CCM5P4X3635

Spellman高压发生器维修Perkin Elmer分析仪电源维修CCM5P4X3635 Perkin Elmer W102266 X射线高压发生器spellman电源维修X4297系列CT机高压电源维修CT42&#xff1b;CT70系列。SPELLMAN高压发生器应用于东芝CT机XVISION/EX、AUKLET系列、ASTEION系列、以及多排系列&#xff0c…

一文概括|CSC访问学者/博士后/联培申请及派出流程详解

为帮助申请者了解国家留学基金委&#xff08;CSC&#xff09;的政策&#xff0c;以及申报及派出的全过程&#xff0c;知识人网小编利用本文简略介绍并提出规划建议。 公派留学包括国家、地方&#xff08;含省市、行业、学校医院等单位&#xff09;资助派出。而国家公派则由留学…

HarmonyOS开发篇—数据管理(分布式数据服务)

分布式数据服务概述 分布式数据服务&#xff08;Distributed Data Service&#xff0c;DDS&#xff09; 为应用程序提供不同设备间数据库数据分布式的能力。通过调用分布式数据接口&#xff0c;应用程序将数据保存到分布式数据库中。通过结合帐号、应用和数据库三元组&#xf…

软件测试实训系统建设方案2024

软件测试实训室解决方案 一 、方案概述 软件测试实训解决方案是一个复杂且至关重要的过程&#xff0c;它确保了软件在开发过程中的各个模块能够正确地集成和交互。通过这一系列的测试步骤&#xff0c;开发团队能够及时发现并修复潜在的问题&#xff0c;从而提高软件的整体质量…

【漏洞复现-通达OA】通达OA share存在前台SQL注入漏洞

一、漏洞简介 通达OA&#xff08;Office Anywhere网络智能办公系统&#xff09;是由北京通达信科科技有限公司自主研发的协同办公自动化软件&#xff0c;是与中国企业管理实践相结合形成的综合管理办公平台。通达OA为各行业不同规模的众多用户提供信息化管理能力&#xff0c;包…

【Java EE初阶十五】网络编程TCP/IP协议(二)

1. 关于TCP 1.1 TCP 的socket api tcp的socket api和U大片的socket api差异很大&#xff0c;但是和前面所讲的文件操作很密切的联系 下面主要讲解两个关键的类&#xff1a; 1、ServerSocket&#xff1a;给服务器使用的类&#xff0c;使用这个类来绑定端口号 2、Socket&#xf…

全网最容易理解的KMP算法讲解

引言 其实网上有很多讲解KMP算法的文章&#xff0c;详略不一&#xff0c;我认为有两点没有解释清楚&#xff1a; 第一点&#xff1a;匹配失败以后&#xff0c;模式串的位移 第二点&#xff1a;next数组的生成算法 希望本篇文章能将KMP算法清晰易懂的拆解开来。 暴力匹配 …

网络同步—帧同步和状态同步解析

概述 同步就是要多个客户端表现效果是一致的&#xff0c;而且对于大多数的游戏&#xff0c;不仅仅要表现一致&#xff0c;还要客户端和服务器的数据也是一致的。所以同步是个网络游戏概念&#xff0c;只有网络游戏才需要同步&#xff0c;而单机游戏是不需要同步的。 帧同步和…

算法-3-基本的数据结构

单双链表 1.单链表双链表如何反转 import java.util.ArrayList; import java.util.List;public class Code01_ReverseList {public static class Node {public int value;public Node next;public Node(int data) {value data;}}public static class DoubleNode {public int…

掘根宝典之C++深复制与浅复制(复制构造函数,默认复制构造函数)

到目前为止我们已经学了构造函数&#xff0c;默认构造函数&#xff0c;析构函数&#xff1a;http://t.csdnimg.cn/EOQxx 转换函数&#xff0c;转换构造函数&#xff1a;http://t.csdnimg.cn/kiHo6 友元函数&#xff1a;http://t.csdnimg.cn/To8Tj 接下来我们来学习一个新函数…

python毕设选题 - 大数据全国疫情数据分析与3D可视化 - python 大数据

文章目录 0 前言1 课题背景2 实现效果3 设计原理4 部分代码5 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的…

2024阿里云云服务器ECS价格表出炉

2024年最新阿里云服务器租用费用优惠价格表&#xff0c;轻量2核2G3M带宽轻量服务器一年61元&#xff0c;折合5元1个月&#xff0c;新老用户同享99元一年服务器&#xff0c;2核4G5M服务器ECS优惠价199元一年&#xff0c;2核4G4M轻量服务器165元一年&#xff0c;2核4G服务器30元3…

【Funny Game】 人生重开模拟器

目录 【Funny Game】 人生重开模拟器&#xff01; 人生重开模拟器&#xff01; 文章所属专区 Funny Game 人生重开模拟器&#xff01; 人生重开模拟器&#xff0c;让你体验从零开始的奇妙人生。在这个充满惊喜和挑战的游戏中&#xff0c;你可以自由选择性别、出生地、家庭背景…

String.format()详细用法

String 类有一个强大的字符串格式化方法 format()。下面是常用的方法总结。 一、占位符类型 String formatted String.format("%s今年%d岁。", "小李", 25); // "小李今年25岁。" 二、字符串和整数格式化 // 将第二个入参拼接到模板中,入参长…