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

C++语法规则2(C++面向对象)

继承

面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。在 Qt 里大量的使用了这种特性,当 Qt 里的类不满足自己的要求时,我们可以重写这个类,就是通过继承需要重写
的类,来实现自己的类的功能。

一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:

class derived-class: access-specifier base-class 

与类的访问修饰限定符一样,继承的方式也有几种。其中,访问修饰符 access-specifier 是 public、protected 或 private 其中的一个,base-class 是之前定义过的某个类的名称。如果未使用访问修饰符 access-specifier,则默认为 private。

下面来捋一捋继承的方式,例子都是以公有成员和公有继承来说明,其他访问修饰符和其他继承方式,大家可以在教程外自己捋一捋。这个公有成员和继承方式也没有什么特别的,无非就是不同的访问权限而已,可以这样简单的理解。

1. 公有继承(public):当一个类派生继承公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。

2. 保护继承(protected): 当一个类派生继承保护基类时,基类的公有和保护成员将成为派生类的保护成员。

3. 私有继承(private):当一个类派生继承私有基类时,基类的公有和保护成员将成为派生类的私有成员。

下面我们还是以狗类为例,在 2.2.1 小节里我们定义的狗类,已经定义了 name,age 和 run()方法。假设我们不想重写这个狗类,而是新建一个 Animal 类,让狗类去继承这个 Animal 类。

假设是公有继承,那么我们是不是可以在狗类实例的对象里去使用继承 Animal 类里的成员呢?带着这个疑问,我们使用下面的例子来说明。

新建一个目录 06_inherit_example,编辑一个 06_inherit_example.cpp 内容如下。

1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 /*动物类,抽象出下面两种属性, 6 *颜色和体重,是每种动物都具有的属性 7 */ 8 class Animal 9 { 10 public: 11 /* 颜色成员变量 */ 12 string color; 13 /* 体重成员变量 */ 14 int weight; 
15 }; 16 17 /*让狗类继承这个动物类,并在狗类里写自己的属性。 18 *狗类拥有自己的属性 name,age,run()方法,同时也继承了 19 *动物类的 color 和 weight 的属性 20 */ 21 class Dog : public Animal 22 { 23 public: 24 string name; 25 int age; 26 void run(); 27 }; 28 29 int main() 30 { 31 Dog dog; 32 dog.name = "旺财"; 33 dog.age = 2; 34 dog.color = "黑色"; 35 dog.weight = 120; 36 cout<<"狗的名字叫:"<<dog.name<<endl; 37 cout<<"狗的年龄是:"<<dog.age<<endl; 38 cout<<"狗的毛发颜色是:"<<dog.color<<endl; 39 cout<<"狗的体重是:"<<dog.weight<<endl; 40 return 0; 41 } 

第 21 行,Animal 作为基类,Dog 作为派生类。Dog 继承了 Animal 类。访问修饰符为 public(公有继承)。
执行下面的指令开始编译。

g++ 06_inherit_example.cpp -o 06_inherit_example 

编译完成执行的结果为如下。
在这里插入图片描述

重载

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。

重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。

函数重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。我们不能仅通过返回类型的不同来重载函数。在 Qt源码里,运用了大量的函数重载,所以我们是有必要学习一下什么是函数重载。不仅在 C++,在其他语言的里,都能看见函数重载。因为需要不同,所以有重载各种各样的函数。

下面通过一个小实例来简单说明一下函数重载的用法。我们还是以狗类为说明,现在假设有个需求。我们需要打印狗的体重,分别以整数记录旺财的体重和小数记录旺财的体重,同时以整数打印和小数打印旺财的体重。那么我们可以通过函数重载的方法实现这个简单的功能。

新建一个目录 07_func_overloading,编辑一个 07_func_overloading.cpp 内容如下。

1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Dog 6 { 7 public: 8 string name; 9 void getWeight(int weight) { 10 cout<<name<<"的体重是:"<<weight<<"kG"<<endl; 11 } 12 13 void getWeight(double weight) { 14 cout<<name<<"的体重是:"<<weight<<"kG"<<endl; 15 } 16 }; 17 18 int main() 19 { 20 Dog dog; 21 dog.name = "旺财"; 22 dog.getWeight(10); 23 dog.getWeight(10.5); 24 return 0; 25 } 

第 9 行,写了一个方法 getWeight(int weight),以 int 类型作为参数。

第 13 行,以相同的函数名 getWeight,不同的参数类型 double weight,这样就构成了函数重载。

第 22 行与第 23 行,分别传进参数不同的参数,程序就会匹配不同的重载函数。
执行下面的指令编译。

g++ 07_func_overloading.cpp -o 07_func_overloading 

程序执后的结果如下。
在这里插入图片描述

通过上面的例子我们可以知道重载函数的使用方法,避免用户传入的参数类型,有可能用户传入的参数类型不在我们写的重载函数里,假若用户传入了一个字符串类型,这样编译器就会匹配不到相应的重载函数,编译时就会报错。其实我们还可以多写几个重载函数,设置多几
种类型,如 string 类型,char 类型,float 类型等。

运算符重载

运算符重载的实质就是函数重载或函数多态。运算符重载是一种形式的 C++多态。目的在于让人能够用同名的函数来完成不同的基本操作。要重载运算符,需要使用被称为运算符函数的特殊函数形式,运算符函数形式:operatorp(argument-list),operator 后面的’p’为要重载的运
算符符号。重载运算符的格式如下:

<返回类型说明符> operator <运算符符号>(<参数表>) 
{ <函数体> } 

下面是可重载的运算符列表:
在这里插入图片描述
在这里插入图片描述
下面是不可重载的运算符列表:
在这里插入图片描述
根据上表我们知道可以重载的运算符有很多,我们以重载“+”运算符为例,实际上用重载运算符我们在实际应用上用的比较少,我们只需要了解和学习这种思想即可。

下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用 this 运算符进行访问。下面还是以我们熟悉的狗类为例。声明加法运算符用于把两个 Dog 对象相加的体重相加,返回最终的 Dog 对象然后得到第三个 Dog 对象的体重。

新建一个目录 08_operator_example,编辑一个 08_operator_example.cpp 内容如下。

1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Dog 6 { 7 public: 8 int weight; 9 Dog operator+(const Dog &d) { 10 Dog dog; 11 dog.weight = this->weight + d.weight; 12 return dog; 13 } 14 15 }; 16 17 int main() 18 { 19 Dog dog1; 20 Dog dog2; 21 Dog dog3; 
22 23 dog1.weight = 10; 24 dog2.weight = 20; 25 dog3 = dog1 + dog2; 26 cout<<"第三只狗的体重是:"<<dog3.weight<<endl; 27 return 0; 28 } 

第 9 至 13 行,重载“+”运算符,注意函数必须与类名同名,把 Dog 对象作为传递,使用 this 运算符进行访问。然后返回一个 dog 对象。
执行下面指令进行编译。

g++ 08_operator_example.cpp -o 08_operator_example 

编译完成后运行的结果如下。
在这里插入图片描述

结果可以预知的,重载运算符“+”,可以把两个对象进行相加。在普通的算术运算符“+”是不能将两个对象进行相加的,所以我们重载运算符的意义可以体现在这里。

多态

C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数;

形成多态必须具备三个条件:

1. 必须存在继承关系;
2. 继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字 virtual 声明的函数,在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数);
3. 存在基类类型的指针或者引用,通过该指针或引用调用虚函数。

这里我们还需要理解两个概念:

虚函数:

是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。虚函数声明如下:virtual
ReturnType FunctionName(Parameter) 虚函数必须实现,如果不实现,编译器将报错

纯虚函数:

若在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。纯虚函数声明如下:

virtual void funtion1()=0; 纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口。

包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。

上面那些概念大家可以捋一捋,毕竟 C++概念还是挺多的。为什么说到多态要与虚函数和纯虚函数扯上关系?光说概念没有实例确实难理解。下面我们还是以我们熟悉的狗类和动物类,另外加一个猫类进行多态的讲解。

相关文章:

C++语法规则2(C++面向对象)

继承 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。这样做&#xff0c;也达到了重用代码功能和提高执行效率的效果。 当创建一个类时&#xff0c;您不需要重新编写新的数据成员和成…...

第八批国家药品集中采购-(附药品集采目录明细下载)

2023年3月2日&#xff0c;‘国家组织药品联合采购办公室’发出了《全国药品集中采购文件》&#xff0c;宣告了第八批国家组织药品集中采购工作正式开展&#xff0c;其公告中还包含三个附表分别为‘采购品种目录’、‘各地区首年约定采购量’、‘各采购品种首年约定采购量’&…...

政府工作报告连提9年科技创新 企业研发如何“又快又好”

今年的政府工作报告&#xff0c; “科技创新” 这一描述连续出现7次&#xff0c;这也是自2015年开始&#xff0c; “科技创新” 这一概念在全国“两会”政府工作报告中连续九年被提到。政府工作报告指出&#xff0c;科技政策要聚焦自立自强&#xff0c;完善新型举国体制&#x…...

GM8773C 是一款 1:2 DSI 桥接芯片,可实现 4 路进 8 路出转换器功能、视频分离器功能。

GM8773C 是一款 1&#xff1a;2 DSI 桥接芯片&#xff0c;可实现 4 路进 8 路出转换器功能、视频分离器功能。芯片内集成了一个 4 路单一链路的 MIPI DSI 接收器和 8 路双链路 MIPI DSI 发送器。 接 收 器 每 路 可 以 支 持 到 2.0Gbps/lane &#xff0c; 可 以 最 高 支 持 到…...

Java常用包名和说明

包名主要功能java.applet提供了创建applet需要的所有类java.awt.*提供了创建用户界面以及绘制和管理图形、图像的类java.beans.*提供了开发Java Beans需要的所有类java.io提供了通过数据流、对象序列以及文件系统实现的系统输入、输出java.lang.*Java编程语言的基本类库java.ma…...

dva01-初识

背景 React 本身只是一个 DOM 的抽象层&#xff0c;使用组件构建虚拟 DOM。如果开发大应用&#xff0c;还需要解决一个问题。 通信&#xff1a;React 只提供了一种传参手段&#xff0c;后续数据变化非常麻烦&#xff0c;无法适用于大应用。数据流&#xff1a;每次要更新数据&…...

信捷 XDH Ethercat A_WRITE指令

本指令修改指令轴的当前位置。 什么时候需要用本指令呢&#xff1f;换句话说&#xff0c;用本指令后&#xff0c;坐标原点修改了偏移了。如果在回原点后&#xff0c;往前走了一段距离x,如果是用绝对模式执行把位置修改成0&#xff0c;那么下一次开始每次做绝对运动A_MOVEA&…...

Spring Cloud ( Eureka集群的搭建 )

操作步骤&#xff1a; 添加主机映射创建Eureka服务 导入依赖编写启动类编写yml复制服务实例测试一、添加主机映射 以 Windows系统为例&#xff0c;如果要构建集群&#xff0c;需要修改 hosts 文件&#xff0c;为其添加主机名的映射。 打开C:\Windows\System32\drivers\etc\h…...

Python re 模块

正则表达式是一种小型、高度专业化的编程语言。适用于任何语言&#xff0c;在 Python 中通过 re 模块实现。正则模式被编译成一系列的字节码&#xff0c;然后由 C 语言编写的匹配引擎执行。给字符串模糊匹配 正则用于匹配字符串&#xff0c;匹配字符串可以完全匹配和模糊匹配&…...

为什么越来越多的人开始学习大数据

因为根据国内的发展形势&#xff0c;大数据未来的发展前景会非常好&#xff0c;前景好需求高&#xff0c;自然会吸引越来越多的人进入大数据行业 我国市场环境处于急需大数据人才但人才不足的阶段&#xff0c;所以未来大数据领域会有很多的就业机遇。 2022年春季&#xff0c;…...

【C++】C++核心编程(二)---引用

1.基本语法 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &别名 原名&#xff08;int &b a&#xff0c;其中别名与原名的数据类型必须一致&#xff09; 注意事项&#xff1a; 引用必须初始化引用在初始化后&#xff0c;就不可以再改变了 代码演示&am…...

原型设计模式

介绍 原型模式 在Java中,原型模式是一种创建型设计模式,它允许通过复制一个现有对象来创建一个新对象,而不是通过创建新的对象来初始化一个对象,原型模式是一种基于克隆的设计模式,通过复制现有对象的数据来创建新的对象. 原型模式需要实现Cloneable接口并重写Object类中的c…...

JVM结构-类加载(类加载子系统,类加载的角色,类加载的过程,类加载器分类,双亲委派机制,类的主/被动使用)

JVM 结构-类加载2.1类加载子系统2.2类加载的角色2.3类加载的过程2.3.1加载2.3.2链接2.3.3初始化2.4类加载器分类2.4.1 引导类加载器2.4.2扩展类加载器2.4.3应用程序类加载器2.5双亲委派机制2.6类的主动/被动使用2.1类加载子系统 类加载器子系统负责从文件系统或者网络中加载 cl…...

vcpkg私有port的创建和使用

1,准备环境: 系统:windows 系统 2, 安装vcpkg 步骤一 :先git clone下载下来vcpkg文件夹 命令:git clone “https://github.com/Microsoft/vcpkg.git” 步骤二:添加vcpkg环境变量 例如下载目录:D:\woker_zj 步骤三:编译vcpkg 操作:双击bootstrap-vcpkg.bat 步骤四: 为…...

LeetCode——203. 移除链表元素

对于初学链表的学者来学&#xff0c;链表是比较困难的&#xff0c;这部分对指针结构体的要求比较高。我们通过练习是掌握知识的重要途经203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09;我们在数组中去除某元素是遍历一遍数组&#xff0c;如果某位置是要去除的元素&a…...

[Java Web]Request对象 | 超1w字带你熟悉Servlet中的request请求

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章 ⭐所属专栏&#xff1a;Java Web ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601; 目录 Reque…...

求一个补码表示数的原始值的三种方式

求一个补码表示数的原始值的三种方式假设 a(10010)2′complement−14a (10010)_{2complement}-14a(10010)2′complement​−14 方式1&#xff0c;通过补码求原始值公式求值&#xff08;see article&#xff09; x−xM−1∗2M−1∑i0M−2xi∗2ix-x_{M-1}*2^{M-1}\sum_{i0}^{M-2…...

【计算机组成原理】

第2章 运算方法和运算器 2.1 数据与文字的表示方法 2.1.1 数据格式 定点数的表示方法 定点纯小数纯小数表示范围定点纯整数定点表示法特点 浮点数的表示方法&#xff1a; 浮点的规格化表示&#xff1a;阶码、尾数、指数、基数IEEE754标准&#xff1a;单精度、双精度浮点数表…...

论文分享:图像识别与隐私安全

1、基于差分隐私框架的频域下人脸识别隐私保护算法Privacy-Preserving Face Recognition with Learnable Privacy Budget in Frequency Domain2、一种基于视觉密码学和可信计算的无密钥依赖的医学图像安全隐私保护框架A Privacy Protection Framework for Medical Image Securi…...

计算机基础小结

目录 ❤ 计算机基础编程 什么是编程语言? 什么是编程? 为什么要学习编程? ❤ 计算机组成原理 控制器 运算器 储存器 内存(主存) 外存 输入设备 输出设备 适配器 总线 机械硬盘 固态硬盘 ❤ 计算机操作系统 什么是操作系统? 什么是文件? 什么是应…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...

Linux-进程间的通信

1、IPC&#xff1a; Inter Process Communication&#xff08;进程间通信&#xff09;&#xff1a; 由于每个进程在操作系统中有独立的地址空间&#xff0c;它们不能像线程那样直接访问彼此的内存&#xff0c;所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...

表单设计器拖拽对象时添加属性

背景&#xff1a;因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...