C++进阶--继承

news2024/9/22 13:40:58

概念

继承,允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法
继承的主要目的是实现代码的重用和构建类之间的层次关系。通过继承,子类可以获得父类的特性,包括数据成员和成员函数,而无需重新编写相同的代码。

定义

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

class Student : public Person
{
protected:
	int _SId;
};

class Teacher :public Person
{
protected:
	int _TId;
};

int main()
{
	Student s;
	
	Teacher t;
	s.Print();
	t.Print();

	return 0;
}

格式

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

可以看出,基类的private成员在派生类无论以何种方式继承都是不可见的这里的不可见是虽然基类的成员仍然被继承到了,但在语法上限制了对private成员的访问,也就说如果要初始化派生类的继承成员,是没被办法初始化的
基类的protected成员以任何方式继承都是可以的,但是不同的继承方式展示出不同的权限;
使用关键字class默认继承方式是private,使用关键字struct默认继承方式是public,但还是写出继承方式比较好;
在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承。

基类和派生类的赋值转换

1.派生类对象可以赋值给基类的对象/基类的指针/基类的引用。由于子类可能会比父类多一些成员什么的,当派生类赋值给基类时,会切割基类没有的数据成员和成员函数,这种做法被称为“切片”;
2.基类对象不能赋值给派生类对象
3.基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用

class Person
{
protected:
	string _name="PersonName"; // 姓名
	string _sex; // 性别
	int _age=10; // 年龄
};
class Student : public Person
{
public:
	void Print()
	{
		cout<<"-name:" << _name << endl;
		cout<<"age:" << _age << endl;
		cout << "Personname:" << Person::_name << endl;
	}
protected:
	int _No; // 学号
	string _name="StudentName";
};
int main()
{
	Student s;
	
	//派生类赋值给基类
	Person p1=s;
	Person* p2 = &s;
	Person& p3 = s;

	//基类赋值给派生类
	//s = p1;//基类不能赋值给派生类

	Student* ps1 = (Student*)p2;//可以通过强制类型转换赋值给派生类
	


	return 0;
}

在这里插入图片描述
在这里插入图片描述

继承中的作用域

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

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

在这里插入图片描述

派生类的默认成员函数

1.派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数,那么可以在派生类中的构造函数初始化列表中进行显示调用;
2.派生类的拷贝构造必须调用基类的拷贝构造完成基类的拷贝初始化
3.派生类的赋值必须调用基类的operator=完成基类的复制
4.派生类的析构函数会在被调用完成后再调用基类的析构函数完成清理。这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。

class Person
{
public:
	Person(string name = "hama")
		: _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(string 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; //学号
};

int main()
{
	Student s1("傻风",12);//构造
	Student s2(s1);//拷贝构造
	Student s3("傻怕", 18);//赋值
	s1 = s3;

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

在这里插入图片描述
这个好理解,父亲的朋友怎么会是孩子的朋友呢?除非让父亲的朋友也跟孩子做朋友,当然这样就不叫继承了;
在这里插入图片描述
!](https://img-blog.csdnimg.cn/direct/15e5065f11a04d4bbd198f2eeb6c692d.png)

继承与静态成员

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员,它是独立于基类和派生类之外作用域的;只是恰好在基类中当成员。静态成员伴随着整个运行阶段;

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; // 研究科目
};
int main()
{
	Student s1;
	Student s2;
	Student s3;
	Graduate s4;
	cout << " 人数 :" << Person::_count << endl;
	Student::_count = 0;
	cout << " 人数 :" << Person::_count << endl;
}

在这里插入图片描述

菱形继承

在上面最近代码中,一个子类只有一个父类时这种继承成为单继承;
多继承:一个子类有两个或以上的父类时称这个继承为多继承
菱形继承:如下
在这里插入图片描述
菱形继承的问题:

class A
{
public:
	int _a;
};
// class B : public A
class B :virtual  public A
{
public:
	int _b;
};
// class C : public A
class C :virtual  public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};

在上面代码中,类D同时继承了类C和类B,而类C和类B又都继承了类A,这就构成了菱形继承的情况了;
菱形继承的主要问题是二义性。由于类D继承了两个父类,并且这两个父类都有相同的成员a,编译器无法确定具体调用B类的a还是C类的a给D类继承,从而导致二义性问题;

int main()
{
	D d;
	//虽然菱形继承可以通过显示调用来解决二义性问题,当仍然存在数据冗余
	d.B::_a = 1;
	d.C::_a = 2;

	d._b = 3;
	d._c = 4;
	d._d = 5;

	return 0;
}

在这里插入图片描述
为了解决菱形继承的二义性,C++提供了虚拟继承的机制;就是在类B和类C继承类A时加上关键字virtual,可以告诉编译器在构建类D的对象时只保留一份A类的实例
在这里插入图片描述

在实际应用中,我们很少用到多继承,也就没有菱形继承的问题;

组合和继承

继承和组合是面向对象编程中两种常见的代码复用机制。
继承:继承是一种通过创建新类基于已有类的属性和方法来实现代码复用的机制,子类可以继承父类的所有公有和受保护的成员,并且可以在此基础上添加新的特性或修改现有的行为。通过继承可以实现类之间的“is-a”关系,即子类是父类的一种特殊类型。
组合:组合是通过将一个类的对象作为另一个类的成员来实现代码复用的机制。像我们前面的逆向迭代器,stack和queue都是用到了组合;通过组合,一个类可以拥有其他类的对象,并且可以通过调用这些对象的方法来实现自己的功能。组合主要用于表示“has-a”关系,即一个类包含另一个类的对象。

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

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

相关文章

qt-C++笔记之QStringList、QList<QString>、QString、QChar、QList<QChar>区别

qt-C笔记之QStringList、QList、QString、QChar、QList区别 —— 杭州 2024-01-30 凌晨0:27 参考博文&#xff1a;qt-C笔记之QStringList code review! 文章目录 qt-C笔记之QStringList、QList<QString>、QString、QChar、QList<QChar>区别1.Qt的字符容器类1.QSt…

维护管理Harbor,docker容器的重启策略

维护管理Harbor 通过HarborWeb创建项目 在 Harbor 仓库中&#xff0c;任何镜像在被 push 到 regsitry 之前都必须有一个自己所属的项目。 单击“项目”&#xff0c;填写项目名称&#xff0c;项目级别若设置为"私有"&#xff0c;则不勾选。如果设置为公共仓库&#…

【个人博客搭建】Hexo安装部署

目录 一、本地构建Hexo (一) 安装前提 1. Node.js 2. Git 3. Hexo (二) 初始化Hexo 1. 初始化博客目录 2. 配置网站基本信息 (三) 主题配置 1. 选择主题 2. 下载主题 (四) 本地启动Hexo 1. 生成静态文件 2. 启动服务 二、部署 (一) 部署到Github Pages 1. 新建…

线性代数------矩阵的运算和逆矩阵

矩阵VS行列式 矩阵是一个数表&#xff0c;而行列式是一个具体的数&#xff1b; 矩阵是使用大写字母表示&#xff0c;行列式是使用类似绝对值的两个竖杠&#xff1b; 矩阵的行数可以不等于列数&#xff0c;但是行列式的行数等于列数&#xff1b; 1.矩阵的数乘就是矩阵的每个…

4D毫米波雷达分类和工程实现

4D毫米波目标检测信息丰富&#xff0c;可获得目标3维位置信息、径向速度vr和rcs等&#xff0c;能够对目标准确分类。 4D毫米波和激光做好时空同步&#xff0c;可以用激光目标给4D毫米波做标注&#xff0c;提升标注效率。 1 激光用做4D毫米波分类真值 128线激光推理的结果作为4…

如何从视频中提取高清图片?可以这样截取

如何从视频中提取高清图片&#xff1f;从视频中提取高清图片可以方便我们制作各种用途所需的素材&#xff0c;如海报、社交媒体配图等。此外&#xff0c;高清图片的细节和色彩也更丰富&#xff0c;可以更好地满足我们的视觉需求。从视频中提取高清图片是一项需要技巧的任务&…

windows上使用anconda安装tensorrt环境

windows上使用anconda安装tensorrt环境 1 安装tensorrt1.1 下载最新的稳定的tensorrt 8.6.1(tensorrt对应的cuda、cudnn等版本是参考链接4)1.2 将tensorrt添加到环境变量1.3 安装tensorrt依赖1.4 安装Pycuda1.5 安装pytorch 2 测试2.1 测试TensorRT 样例(这个测试主要来源于参考…

InsideCli、OutsideCli-电源管理(23国赛真题)

2023全国职业院校技能大赛网络系统管理赛项–模块B&#xff1a;服务部署&#xff08;WindowServer2022&#xff09; 文章目录 题目配置步骤验证 题目 设置电源配置&#xff0c;以便客户端在通电的情况下&#xff0c;永不进入睡眠。 配置步骤 验证

小猪o2o生活通系统更新到了v24.1版本了php文件开源了提供VUE了但是车牌识别功能你真得会用吗

一.车牌识别设置项 车牌识别设置项总开关&#xff1a;系统后台-社区管理-社区配置-车牌识别配置。 平台需要开启车牌识别功能&#xff0c;其次平台可以选择车牌识别功能是由平台配置还是小区自己配置有需要提供代码的可以Q我昵称注明&#xff1a;CSDN网友。如果是平台自己配置&…

2024年火爆《幻兽帕鲁》可以macos系统运行吗?

幻兽帕鲁已经爆了&#xff0c;你和朋友们都是在哪个平台一起玩的&#xff1f; 这款有些类似宝可梦的游戏&#xff0c;已经以野火燎原之势席卷互联网&#xff0c;并且势必会持续一段时间&#xff0c;你可别说你不知道。 《幻兽帕鲁》目前能在哪些平台上运行&#xff1f; 这款由…

linux 下gdal库(python)

之前在windows下安装gdal&#xff0c;先要下安装包再安装。这次在linux上安装&#xff0c;试了一下pip install gdal&#xff0c;不可以。想着linux应该一样&#xff0c;结果一搜网上教程一堆&#xff0c;乱七八糟的。 搞了一个小时 最后发现一句话就可以&#xff01;&#xf…

力扣hot100 分割回文串 集合 dfs

Problem: 131. 分割回文串 文章目录 思路Code&#x1f496; DP预处理版 思路 &#x1f468;‍&#x1f3eb; 参考题解 Code import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List;public class Solution {int n;//字符…

基于二值化图像转GCode的斜向扫描实现

基于二值化图像转GCode的斜向扫描实现 什么是斜向扫描斜向扫描代码示例 基于二值化图像转GCode的斜向扫描实现 什么是斜向扫描 在激光雕刻中&#xff0c;斜向扫描&#xff08;Diagonal Scanning&#xff09;是一种雕刻技术&#xff0c;其中激光头沿着对角线方向来回移动&…

上位机图像处理和嵌入式模块部署(视频处理vs图像处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 从目前发展的情况来看&#xff0c;视频处理会慢慢变成一种主流趋势。这里面的原因很多&#xff0c;比如说现在嵌入式soc的算力越来越强、获取图像的…

【大数据安全】大数据安全的挑战与对策基础设施安全

目录 一、大数据安全的挑战与对策 &#xff08;一&#xff09;数据加密技术 &#xff08;二&#xff09;大数据安全与隐私 &#xff08;三&#xff09;大数据安全保障体系 &#xff08;四&#xff09;华为大数据安全解决方案 二、基础设施安全 &#xff08;一&#xff0…

TSINGSEE青犀视频智慧电梯管理平台,执行精准管理、提升乘梯安全

一、方案背景 随着城市化进程的不断加快&#xff0c;我国已经成为全球最大的电梯生产和消费市场&#xff0c;电梯也成为人们日常生活中不可或缺的一部分。随着电梯数量的激增&#xff0c;电梯老龄化&#xff0c;维保数据不透明&#xff0c;物业管理成本高&#xff0c;政府监管…

用React给XXL-JOB开发一个新皮肤(四):实现用户管理模块

目录 一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语 一. 简述 上一篇文章我们实现登录页面和管理页面的 Layout 骨架&#xff0c;并对接登录和登出接口。这篇…

【代码随想录】刷题笔记Day56

前言 26回了老家参加二姨的婚礼&#xff0c;还逛了几圈亲戚&#xff0c;回来就接家教的活&#xff0c;想到还要刷题开组会&#xff0c;回家注定是没法怎么休息啦&#xff0c;可恶 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 暴力解法&#xff08;双指针优化&#xf…

SpringBoot中集成Minio高性能分布式存储文件服务入门

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目-CSDN博客 参考上面搭建项目。 Minio Minio是基于Go语言编写的对象存储服务&#xff0c;适合于存储大容量非结构化的数据&#xff0c;例如图片、音频…

定制自己的linux

记得看目录哦&#xff01; 1. 基本介绍2. 思路分析3. 开始定制3.1 添加一块20G的硬盘3.2 重启&#xff0c;进行磁盘分区3.3 格式化分区3.4 创建目录&#xff0c;并挂载磁盘3.5 安装grub3.6 看是否安装上3.7 内核文件拷贝到磁盘3.8 修改grub2/grub.cfg3.9 创建目标主机的根文件系…