当前位置: 首页 > news >正文

C++笔记---继承(上)

1. 继承的简单介绍

1.1 继承的概念

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称派生类。

继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复用,继承是类设计层次的复用。

简单来说,被继承的类叫做父类(或基类),继承自父类的类叫做子类(或派生类)

子类拥有父类的所有成员,在此基础之上可以对父类进行拓展。

1.2 子类的定义方式

class 子类名 : 访问限定符 父类名
{// 拓展内容
}

通常来说,父类和子类具有类别上的包含关系

例如,老师和同学不仅具有人的基本特点,还在人的基础之上有了自己的拓展,而老师和同学都属于人。

我们在用C++进行描述的时候,就可以将老师和同学设计成人的子类:

人类(父类):

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; // 职称
};

1.3 继承方式

访问限定符限定的是继承的方式,不同访问限定符下的继承方式如下:

类成员 / 继承方式publicprotectedprivate
父类的public成员子类的public成员子类的protected成员子类的private成员
父类的protected成员子类的protected成员子类的protected成员子类的private成员
父类的private成员子类无法直接显式访问子类无法直接显式访问子类无法直接显式访问

子类成员的访问权限:public > protected > private > 父类中被修饰为private

其中,protected访问限定符是伴随着继承的出现而出现的。被它修饰的成员,意味着无法在类外部进行访问,而可以在类内部或其子类中被访问

无论子类以何种方式继承,在父类中被修饰为private的成员子类都不可直接显式访问。

继承方式用于限定继承下来的成员访问权限不能高于继承方式。

当不指定继承方式时,class子类默认为private方式继承,struct子类默认为public方式继承。

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

可以采用protected/private继承的一个例子:

#include<vector>
#define CONTAINER std::vectortemplate<class T>
class stack : private CONTAINER<T>
{
public:void push(const T& x){CONTAINER<T>::push_back(x);}void pop(){CONTAINER<T>::pop_back();}const T& top(){return CONTAINER<T>::back();}bool empty(){return CONTAINER<T>::empty();}
};int main()
{stack<int> st;st.push(1);st.push(2);st.push(3);while (!st.empty()){cout << st.top() << " ";st.pop();} return 0;
}

这里采用了继承vector的方式来实现stack,但我希望用户只用stack的接口而不直接访问vector的成员函数,此时就可以采取protected/private的继承方式。

1.4 继承类模板

相信细心的小伙伴已经发现了,在上面stack的例子中,我们每次调用vector的接口时都对其类域进行了指定,否则会发生编译报错:

error C3861: “push_back”: 找不到标识符

这是因为,模板是按需实例化的,当类模板中的函数没有被调用时,其就不会实例化

我们在实例化stack<T>对象时,vector<T>对象也跟着实例化。但是vector<T>中,只有成员变量和构造函数被实例化了

我们在调用push_back()函数时,由于this指针为stack<T>类型,所以编译器并不会将vector模板中的push_back()函数实例化,而是直接去寻找其定义或声明

所以,继承模板类时,调用父类函数要注意指定类域。

2. 父类和子类的转换

1. public继承的子类对象可以赋值给父类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把子类中父类那部分切出来,父类指针或引用指向的是子类中切出来的父类那部分。

2. 父类对象不能赋值给子类对象。

3. 父类的指针或者引用可以通过强制类型转换赋值给子类的指针或者引用。但是必须是父类的指针是指向子类对象时才是安全的。(这里父类如果是多态类型,可以使用RTTI(Run-Time TypeInformation)的dynamic_cast 来进行识别后进行安全转换)

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. 继承中的作用域及"隐藏"规则

隐藏规则:

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

// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是⾮常容易混淆
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; // 学号
};int main()
{Student s1;s1.Print();return 0;
};

 这里,程序运行的结果为

3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同(分别在父类和子类中定义的函数只会触发隐藏而不会触发函数重载)就构成隐藏。
4. 注意在实际中在继承体系里面最好不要定义同名的成员

class A
{
public:void fun(){cout << "func()" << endl;}
};class B : public A
{
public:void fun(int i){cout << "func(int i)" << i << endl;}
};

此时,B中的fun函数会隐藏掉A中的fun函数,而不会构成重载。

4. 子类的默认成员函数

子类的默认成员函数主要是用于处理父类没有的成员成员变量,父类自身的成员交由其自己的默认成员函数去处理。

4.1 构造函数

子类在构造函数的初始化列表中可以显式调用父类的构造函数对父类成员变量进行初始化,若未显式调用则会调用父类的默认构造函数。

如果没有显式调用父类的构造函数,且父类没有默认构造函数,那么此时就会发生报错。

显式调用父类构造函数的方式是:

父类名(参数列表)
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;
}

4.2 赋值重载

必须要在子类的operator=中显式调用父类的operator=才能按照预期正常的对父类成员进行拷贝,否则只会完成浅拷贝。

要注意,子类的operator=会隐藏父类的operator=,调用父类的operator=需要指定类域。

Student& operator = (const Student& s)
{cout << "Student& operator= (const Student& s)" << endl;if (this != &s){// 构成隐藏,所以需要显⽰调⽤Person::operator =(s);_num = s._num;} return* this;
}

4.3 析构函数

父类的析构函数会在子类的析构函数被调用之后自动调用,无需显式调用。

相关文章:

C++笔记---继承(上)

1. 继承的简单介绍 1.1 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许我们在保持原有类特性的基础上进行扩展&#xff0c;增加方法(成员函数)和属性(成员变量)&#xff0c;这样产生新的类&#xff0c;称派生类。 继承呈…...

气膜体育馆:为学校打造智能化运动空间—轻空间

随着教育体制的逐步升级&#xff0c;学校在提升学生综合素质方面的需求日益增长&#xff0c;特别是在体育场地方面。气膜体育馆作为一种新型的运动空间形式&#xff0c;正在迅速成为学校体育设施的优选方案。凭借其快速搭建、节能环保等优势&#xff0c;气膜馆在全国各地的校园…...

JVM 调优篇5 jvm性能监控

一 jvm性能监控 1.1 概述 性能诊断是软件工程师在日常工作中需要经常面对和解决的问题&#xff0c;在用户体验至上的今天&#xff0c;解决好应用的性能问题能带来非常大的收益。 体会1&#xff1a;使用数据说明问题&#xff0c;使用知识分析问题&#xff0c;使用工具处理问…...

一. Unity实现虚拟摇杆及屏幕自适应功能

手游里面很多类型的游戏都需要用到遥感功能&#xff0c;例如王者荣耀&#xff0c;和平精英等&#xff0c;之前的摇杆功能都是用类似于Easy Touch的插件进行开发的&#xff0c;今天不借助任何插件来实现虚拟摇杆的功能。 一般虚拟摇杆的组成都是由轮盘和遥感的点组成&#xff0c…...

【达梦数据库】mysql 和达梦 tinyint 与 bit 返回值类型差异

测试环境 mysql5.7.44 达梦2024Q2季度版 前言 在mysql 中存在 tinyint&#xff08;1&#xff09;的用法来实现存储0 1 作为boolean的标识列&#xff1b;但是在达梦并不允许使用 tinyint&#xff08;1&#xff09;来定义列&#xff0c;只能使用 tinyint 即 取值范围为&#xff…...

VUE工程中axios基本使用

安装axios npm install axios -s在main.js中引入 import http from axios Vue.prototype.$http = http将其绑定在VUE的prototype属性中 vue工程目录下,新建config文件夹,在config文件夹下新建index.js export default {...

跨服务器执行PowerShell脚本

本机和远程机都要执行 Enable-PSRemoting -Force 远程端关闭公用网络 Get-NetConnectionProfile Set-NetConnectionProfile -Name "未识别的网络" -NetworkCategory Private 本机和远程机都要执行 winrm quickconfig 将远程机ip加入信任列表 cd WSMan::localhost\…...

linux_L2_linux删除文件

linux 删除文件 在Linux下删除文件有多种实现方法&#xff0c;以下是其中几种常见的方法&#xff1a; 方法一&#xff1a;使用rm命令删除单个文件 rm 文件路径例如&#xff0c;删除当前目录下的文件file.txt&#xff1a; rm file.txtQuestion :当你在Linux系统中使用rm命令删…...

系统架构设计师 - 项目管理

项目管理 项目管理&#xff08;1-3分&#xff0c;案例分析 25分&#xff09;立项管理 ★盈亏平衡分析 范围管理 ★★时间管理 ★★★★概述前导图法 PDM(单代号网络图)箭线图法 ADM(双代号网络图) 了解关键路径法总时差自由时差 甘特图 成本管理 ★挣值管理概述指数计算 软件质…...

Spring Boot基础

项目创建 项目启动 请求响应 RestController 1.返回值处理 RestController&#xff1a;这个注解结合了Controller和ResponseBody的功能。它默认将所有处理请求的方法的返回值直接作为响应体内容返回&#xff0c;主要用于构建RESTful API。返回的数据格式通常是JSON或XML&…...

C语言 | Leetcode C语言题解之第402题移掉K位数字

题目&#xff1a; 题解&#xff1a; char* removeKdigits(char* num, int k) {int n strlen(num), top 0;char* stk malloc(sizeof(char) * (n 1));for (int i 0; i < n; i) {while (top > 0 && stk[top] > num[i] && k) {top--, k--;}stk[top]…...

使用Visual Studio Code配置C/C++开发环境的全面指南

目录 引言 一、准备工作 1. 安装Visual Studio Code 2. 安装C/C编译器 3. 配置环境变量&#xff08;仅Windows用户&#xff09; 二、在VS Code中安装C/C扩展 三、创建您的第一个C/C项目 1. 创建项目文件夹 2. 打开项目文件夹 3. 创建源文件 四、配置任务&#xff08;…...

算法练习题26——多项式输出(模拟)

输入格式 输入共有 2 行 第一行 1 个整数&#xff0c;n&#xff0c;表示一元多项式的次数。 第二行有 n1 个整数&#xff0c;其中第 i 个整数表示第 n−i1 次项的系数&#xff0c;每两个整数之间用空格隔开。 输出格式 输出共 1 行&#xff0c;按题目所述格式输出多项式。…...

卷积神经网络经典模型架构简介

【图书推荐】《PyTorch深度学习与企业级项目实战》-CSDN博客 《PyTorch深度学习与企业级项目实战&#xff08;人工智能技术丛书&#xff09;》(宋立桓&#xff0c;宋立林)【摘要 书评 试读】- 京东图书 (jd.com) ImageNet是一个包含超过1 500万幅手工标记的高分辨率图像的数据…...

【Kubernetes】常见面试题汇总(十三)

目录 39.简述 Kubernetes Scheduler 使用哪两种算法将 Pod 绑定到 worker 节点&#xff1f; 40.简述 Kubernetes kubelet 的作用&#xff1f; 41.简述 Kubernetes kubelet 监控 Worker 节点资源是使用什么组件来实现的&#xff1f; 39.简述 Kubernetes Scheduler 使用哪两种算…...

嵌入式QT开发:构建高效智能的嵌入式系统

摘要&#xff1a; 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发&#xff0c;详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程&#xff0c;包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面…...

Linux抢占调度

目录 抢占流程 抢占时机 用户态抢占时机 1、 从系统调用返回用户空间 2、 从中断返回用户空间 内核态抢占时机 1、中断处理程序返回内核空间 可以看到最终是到了 preempt_schedule_irq 2、当内核从non-preemptible&#xff08;禁止抢占&#xff09;状态变成pr…...

k8s中,为什么把pod的服务以deployment的形式通过nodeport对外发布,以及容器和虚拟机的一些区别

deployment是个控制器 主要负责管理pod&#xff0c;来代表k8s集群向外提供稳定的服务。 说&#xff0c;k8s有很多优点。 说k8s的优点&#xff0c;可能先需要说容器提供的便利。 同样的硬件资源 跑几个虚拟机&#xff0c;每个虚拟机上跑几个服务。 就挺重了。风扇呼呼叫 …...

PMP--一模--解题--41-50

文章目录 14.敏捷--方法--回顾--回顾是最重要的一个实践&#xff0c;原因是它能让团队学习、改进和调整其过程。41、 [单选] 新项目中的所有团队成员都希望通过尽快交付价值来获得客户的信任。项目经理了解到一个资源已经在其他项目中与发起人一起工作。某资源似乎在使用个人影…...

Kafka启动关闭及其相关命令kafka启动、状态监控、日常操作

开启zookeeper命令(备注:先进入zookeeper的bin目录) ./zkServer.sh start 关闭zookeeper命令(备注:先进入zookeeper的bin目录) ./zkServer.sh stop Kafka启动命令(备注:先进入kafka目录) 常规模式启动kafka bin/kafka-server-start.sh config/server.properties 进程守…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...