【跟学C++】面向对象三大特征——继承(Study20)

news2024/11/23 21:38:56

文章目录

    • 1、了解继承
    • 2、基类与派生类(父类与子类)
      • 2.1、概念
      • 2.2、案例展示
    • 3、构造顺序与析构顺序
    • 4、继承种类
      • 4.1、私有继承
      • 4.2、保护继承
      • 4.3、多继承
    • 5、总结

 ============================ 【说明】 ===================================================
  大家好,本专栏主要是跟学C++内容,自己学习了这位博主【 AI菌】的【C++21天养成计划】,讲的十分清晰,适合小白,希望给这位博主多点关注、收藏、点赞。
  主要针对所学内容,通过自己的理解进行整理,希望大家积极交流、探讨,多给意见。后面也会给大家更新,其他一些知识。若有侵权,联系删除!共同维护网络知识权利!
 =======================================================================================


1、了解继承

  关于继承,用一个简单通俗的案例说明:大家都知道飞机,那么飞机的种类有太多。
  飞机都有起飞、降落、飞行等功能,但是不同种类的飞机也有差异,如果用C++以最简单的方式来模拟不同飞机,该如何去做?

  之前介绍过类的思想,我们自然可以想到声明两个类。其中飞机Plane类里实现飞机的所有属性,指定飞机类中实现指定飞机的所有属性。
  这种方法虽然有效,但是有些属性会在上每个类中重复实现,比如刚刚所说的起飞、降落、飞行等。因此,提出了一种更有效的方案,即继承

  继承在基类中实现所有通用的功能,从同一个基类可以派生出相似的类,并且在每个派生类中单独实现其特有的属性,从而让每个类都独一无二

  

2、基类与派生类(父类与子类)

2.1、概念

   基类与派生类就如括号内所言:父类与子类

  从图中可以看出,这三个派生类均继承于基类。其中,基类也可以称作超类(父类);派生类也可以叫作子类

基类派生类
草鱼、鲈鱼、武昌鱼、鲤鱼等。
麻雀、鹦鹉、燕子、乌鸦等。

  因此,基类和派生类的关系就一目了然:基类可看做是派生类的总称,它具有派生类最基本的属性。派生类是在基类上的进一步升华,具有自定义的属性和功能。

2.2、案例展示

  我们通过一个简单的案例先来了解下继承的相关流程与操作:

#include<iostream>
using namespace std;


//基类
class  Animal
{
public:
	bool riverAnimal;//水中动物

	//公有属性
	void Lift() {
		if (riverAnimal)
			cout << "Life in river!" << endl;
		else
			cout << "Life not in river!" << endl;

	}

};

//子类:鸟类
 class Bird: public Animal
{

public:
	Bird() {
		riverAnimal = false;

	}
 };

 //子类:鸭类
 class Duck : public Animal
 {
 public:
	 Duck() {

		 riverAnimal = true;
	 }

 };

 //子类:狗类
 class Dog : public Animal
 {
 public:
	 Dog() {

		 riverAnimal = false;
	 }

 };

int main() {

	Bird bird1;
	Duck duck1;
	Dog dog1;

	cout << "bird:";
	bird1.Lift();
	cout << "duck:";
	duck1.Lift();
	cout << "dog:";
	dog1.Lift();


	return 0;
}

3、构造顺序与析构顺序

  之前的文章中学习了构造顺序与析构顺序了解了在实例化对象时,会自动调用类的构造函数;销毁对象时,会自动调用析构函数

  关于构造顺序与析构顺序,可以回到这篇文章:【跟学C++】C++类与对象—构造函数—析构函数(Study10)

  问题:

  但是,如果Dog类是从Animal类派生而来的,创建Dog对象时,先调用Dog的构造函数还是Animal的构造函数?
  另外,实例化对象时,成员属性是在调用构造函数之前还是之后实例化?

  
  实际上,基类Animal在派生类Dog对象之前被实例化,因此,首先构造Dog对象的Animal部分, 这样实例化Dog部分时,成员属性就准备就绪,可以使用了。

  总的来说,在实例化派生类Dog对象时,会先实例化基类Animal的成员属性,再调用基类Animal的构造函数; 再实例化派生类Dog的成员属性,最后调用派生类Dog的构造函数。

  在实例化派生类对象时,构造顺序是先实例化成员属性,再调用构造函数,自顶(基类)向下(派生类)完成。析构顺序是自底(派生类)向顶(基类) ,调用析构函数。

  

4、继承种类

  上面介绍的都是公有继承,比较基础的内容,但是继承还有其他的种类,针对不同的需求,可以设置不同继承方式。

4.1、私有继承

  私有继承不同于公有继承,在指定派生类的基类时使用关键字private,其基本语法如下:

class Base{

//...基类成员属性与方法

};

class Derived : private Base{  //私有继承

//...派生类的成员属性与方法

};

  私有继承意味着在派生类的实例中,基类的所有公有成员和方法都是私有的,不能从外部访问。即:即使是Base类的公有成员方法也只能被派生类使用,而不能通过实例化派生类对象来使用它们

  常见的私有继承案例:

基类派生类
MotorCar(汽车,汽车有发动机)
MoonSky(太空,太空有月亮)
AnimalZoo(动物园,动物园有动物)

  通过一个私有继承案例,了解一下:

#include <iostream>
using namespace std;

class Motor //基类 发动机
{
public:
	void SwitchIgnition()//点火开关
	{
		cout << "Ignition ON" << endl; //点火开关ON
	}
	void PumpFuel()//泵燃油
	{
		cout << "Fuel in cylinders" << endl;//气缸中的燃油
	}
	void FireCylinders()//消防气瓶
	{
		cout << "Vroooom" << endl;
	}
};

//子类 汽车
class Car:private Motor // 私有继承  
{
public:
	void Move()
	{
		SwitchIgnition();
		PumpFuel();
		FireCylinders();
	}
};

int main()
{
	Car myDreamCar;
	myDreamCar.Move();
	return 0;
}

   Car类使用关键字 private 私有继承了Motor类,Motor类中的成员方法(函数)只能被Car使用,不能被Car类的实例化对象使用。

   下面展示错误示例:

Car myDreamCar;
myDreamCar.SwitchIgnition();//不可以被Car类的实例化对象使用

4.2、保护继承

   保护继承与公有继承有一定的差异,再声明派生类继承基类的时候使用关键字protected,基本的语法如下:

class Base{

//...基类成员属性与方法

};

class Derived : protected Base{ //保护继承

//...派生类的成员属性与方法

};

   私有继承与保护继承的相似点:

    ● 保护继承也让派生类能够访问基类的所有公有和保护成员;
    ● 在继承层次结构外面,也不能通过派生类实例访问基类的公有成员。

   随着继承层次结构的加深,保护继承与私有继承也有不同之处

class Derived2: protected Derived
{
// 派生类Derived2能够访问基类的所有公有和保护成员
};

   使用保护继承,派生类Derived2能够访问基类的所有公有和保护成员。这在私有继承中是不被允许的

   通过下述案例来理解一下,RaceCar类保护继承了Car类,Car类保护继承了Motor类:

#include <iostream>
using namespace std;

class Motor //基类 发动机
{
public:
	void SwitchIgnition()//点火开关
	{
		cout << "Ignition ON" << endl; //点火开关ON
	}
	void PumpFuel()//泵燃油
	{
		cout << "Fuel in cylinders" << endl;//气缸中的燃油
	}
	void FireCylinders()//消防气瓶
	{
		cout << "Vroooom" << endl;
	}
};


class Car :protected Motor //保护继承
{
public:
	void Move()
	{
		SwitchIgnition();
		PumpFuel();
		FireCylinders();
	}
};

class RaceCar :protected Car //保护继承
{
public:
	void Move()
	{
		SwitchIgnition();
		PumpFuel(); 
		FireCylinders(); 
	}
};

int main()
{
	RaceCar myDreamCar;
	myDreamCar.Move();

	return 0;
}

   注释: Car类以保护方式继承了Motor类,而RaceCar类以保护方式继承了Car类, RaceCar:Move( )的实现使用了基类Motor中定义的公有方法。能否经由中间基类Car访问终极基类Motor的公有成员呢?这取决于Car和Motor之间的继承关系。如果继承关系是私有的,而不是保护的,RaceCar 将不能访问Motor类的公有成员,编译器根据最严格的访问限定符来确定访问权

4.3、多继承

   多继承,顾名思义,即:一个类可以继承多个基类的特性。多继承语法如下:

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,{
	<派生类类体>
};

   访问修饰符继承方式是public、protected 或private其中的一个,用来修饰每个基类,各个基类之间用','逗号分隔。

#include <iostream>
using namespace std;

// 基类 Shape
class Shape
{
public:
	void setWidth(int w)
	{
		width = w;
	}
	void setHeight(int h)
	{
		height = h;
	}
protected:
	int width;
	int height;
};

// 基类 PaintCost
class PaintCost
{
public:
	int getCost(int area)
	{
		return area * 80;
	}
};

// 派生类
class Rectangle : public Shape, public PaintCost
{
public:
	int getArea()
	{
		return (width * height);
	}
};

int main(void)
{
	Rectangle Rect; //实例化对象 
	int area;

	Rect.setWidth(15);
	Rect.setHeight(21);

	area = Rect.getArea();

	// 输出对象的面积
	cout << "Total area: " << Rect.getArea() << endl;

	// 输出总花费
	cout << "Total paint cost: $" << Rect.getCost(area) << endl;

	return 0;
}

5、总结

  最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,我也会及时更新,来督促自己学习进度。一开始提及的博主【AI菌】,个人已关注,并订阅了相关专栏(对我有帮助的),希望大家觉得不错的可以点赞、关注、收藏。

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

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

相关文章

十五、类加载器、反射

类加载器 1类加载器【理解】 作用 负责将.class文件&#xff08;存储的物理文件&#xff09;加载在到内存中 2类加载的过程【理解】 类加载时机 创建类的实例&#xff08;对象&#xff09;调用类的类方法访问类或者接口的类变量&#xff0c;或者为该类变量赋值使用反射方式来…

excel制表基础:规范的制表理念和思路让效率提升 下篇

在日常工作中我们会构建很多的表格&#xff0c;其实这些表格无论多少&#xff0c;都可以归结为三大类&#xff0c;分别为“源数据表”、“关系信息表”和“统计分析表”。上次我们提到了一套表格“统计的核心”——“源数据表”&#xff0c;今天继续为大家分享“关系信息表”和…

力扣(LeetCode)1802. 有界数组中指定下标处的最大值(C++)

贪心二分查找 贪心性质&#xff1a;对于数组中确定位置index的数&#xff0c;要使nums[index]最大&#xff0c;等于使得整个数组之和最小。 提示 &#xff1a;数组相邻元素之差的绝对值小于1&#xff0c;为了数组之和最小&#xff0c;从index往左&#xff0c;形成公差为1的递减…

python实现多张多格式图片转PDF并打包成exe

目录 主要思路 转PDF初始代码 转PDF最终代码 GUI界面设计代码 打包成可执行文件 完整代码 附录 主要思路 从文件夹中读取图片数据&#xff0c;然后将他们保存为PDF格式。 转PDF初始代码 不长&#xff0c;大概10行代码。 from PIL import Image from os import *def …

Stardust 案例:制作散景光斑

本文介绍使用 Ae 插件 Stardust 制作散景光斑的一般方法与步骤。效果视频1、新建合成。持续时间&#xff1a;10 秒。2、新建纯色图层&#xff0c;命名为“散景光斑”&#xff0c;然后添加 Stardust 效果。3、设置 Emitter&#xff08;发射器&#xff09; 。用一个长方形的发射器…

2023外贸人出国抢单攻略(附带2023年全球重要展会)

自11月底以来&#xff0c;全国陆续传来政府带团出国抢单的消息&#xff0c;让沉寂了3年之久的外贸行业热情高涨。这不仅预示着3年抗疫斗争的胜利&#xff0c;更意味着中国三驾马车之一的外贸行业开启了高速运转的车轮。“浙江带领万家企业去欧洲抢单&#xff01;”“福建省商务…

少儿Python每日一题(10):手机键盘

原题解答 本次的题目如下所示(原题出处:NOC) 一般的手机的键盘是这样的: 要按出英文字母就必须要按数字键多下。例如要按出 x 就得按 9 两下,第一下会出 w,而第二下会把 w 变成 x。0 键按一下会出一个空格。 你的任务是读取若干句只包含英文小写字母和空格的句子,求出要…

装备制造业ERP软件如何帮助企业做好物料齐套管理?

在生产制造过程中&#xff0c;要想提高生产效率&#xff0c;齐套管理是很重要的一环&#xff0c;会直接影响库存、交付和效率。而装备制造行业原料种类特别多&#xff0c;通用件也非常多&#xff0c;齐套检查工作十分复杂&#xff0c;深受以下问题困扰&#xff1a;1.装备制造业…

springmvc源码之HandlerMapping处理器映射器

系列文章目录 springmvc源码之Web上下文初始化 springmvc源码之DispatcherServlet前端控制器 springmvc源码之HandlerMapping处理器映射器 文章目录系列文章目录HandlerMapping处理器映射器实现类配置mvc:annotation-driven配置的作用RequestMappingHandlerMapping源码创建访问…

JAVA SpringBlade 微服务开发平台框架,企业级的SaaS多租户微服务平台,基于Spring Boot 2.7

SpringBlade微服务开发平台 完整代码下载地址:JAVA SpringBlade 微服务开发平台框架,企业级的SaaS多租户微服务平台 采用前后端分离的模式&#xff0c;前端开源两个框架&#xff1a;Sword (基于 React、Ant Design)、Saber (基于 Vue、Element-UI)后端采用SpringCloud全家桶&…

【谷粒商城基础篇】前端开发基础知识

谷粒商城笔记合集 分布式基础篇分布式高级篇高可用集群篇简介&环境搭建项目简介与分布式概念&#xff08;第一、二章&#xff09;基础环境搭建&#xff08;第三章&#xff09;整合SpringCloud整合SpringCloud、SpringCloud alibaba&#xff08;第四、五章&#xff09;前端知…

Unity-ROS2与URDF导入(三)

0. 简介 在我们上一章讲的对于Unity与ROS之间的通信&#xff0c;Toolbox等比较基础的指令。下面我们将结合代码来介绍一下如何导入URDF文件&#xff0c;并通过键盘完成Unity的控制。 1. URDF模型创建 首先先创建并编辑URDF文件&#xff0c;并命名为toio_style.urdf <?x…

Python(九)Tornado web 框架

一、简介 Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像web.py 或者 Google 的 webapp&#xff0c;不过为了能有效利用非阻塞式服务器环境&#xff0c;这个 Web 框架还包含了一些相关有用工具及优化。 Tornado 和…

LeetCode:13. 罗马数字转整数

13. 罗马数字转整数1&#xff09;题目2&#xff09;思路3&#xff09;代码4&#xff09;结果1&#xff09;题目 罗马数字包含以下七种字符: I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V …

【自学Java】Java switch语句

Java switch语句 Java switch语句教程 在 Java 语言 中如果遇到多选一的场景&#xff0c;可以使用 switch 将其简化&#xff0c;让程序更加简洁易懂。switch 语句可以被 if…else 代替。它里面包含 switch、case、default 和 break 关键字。 switch 中存放的是对应的被比较的…

题402.数位dp-acwing-1082. 数字游戏1083. Windy数1085. 不要62

文章目录题402.数位dp-acwing-1082. 数字游戏一、题目二、题解三、类似题目四、关于数位dp题402.数位dp-acwing-1082. 数字游戏 一、题目 二、题解 欲求区间[X,Y]中满足性质的数的个数&#xff0c;我们可以想着去求小于m的数中满足性质的个数f(m)&#xff0c;然后利用前缀和思…

WebDAV之葫芦儿·派盘+FX播放器

FX播放器 支持WebDAV方式连接葫芦儿派盘。 想要把手机、PC、NAS等设备上的视频在智能电视上大屏播放,支持超多格式的多合一视频播放器?快来试试FX播放器吧。 FX播放器除了存储在智能手机上的视频外,您网络上的视频也是实时无缝的࿰

关于TCP通信的学习和应用案例

记录学习TCP通信的过程&#xff0c;包括理论知识、在Qt中建立TCP服务端和客户端&#xff0c;并附上源代码。由于最近的项目中也使用到了海康VisionMaster软件&#xff0c;可以将其作为服务端&#xff0c;用Qt写的TCP客户端和其进行通信测试&#xff0c;方便调试。 目录1.关于TC…

MATLAB APP 设计实践(一)UART通信(上篇)

引言UART通信属于异步串行通信&#xff0c;通信速率比较低&#xff0c;在一些速度要求不高的场合常用来作为多设备之间的控制与被控制方式。例如以UART串口通信作为上位机侧与运行设备之间的通信形式&#xff0c;实现上位机对设备的操控以及检测设备运行状态等。那么谈到了上位…

PyTorch实战1

传送门&#xff1a;蓝桥云课实验 目录1. 实验环境2. 实验目的3. 相关原理4. 实验步骤4.1 数据预处理4.1.1 对于类型变量的处理4.1.2 对于数值类型变量进行标准化4.1.3 数据集分割4.2 创建模型手写用Tensor运算的人工神经网络4.3 训练模型4.3.1 数据的分批次处理4.4 测试模型1. …