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

news2024/11/27 17:48:09

继承

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

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。在 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++概念还是挺多的。为什么说到多态要与虚函数和纯虚函数扯上关系?光说概念没有实例确实难理解。下面我们还是以我们熟悉的狗类和动物类,另外加一个猫类进行多态的讲解。

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

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

相关文章

SpringBoot修改启动图标(详细步骤)

目录 一、介绍 二、操作步骤 三、介绍Java学习&#xff08;题外话&#xff09; 四、关于基础知识 一、介绍 修改图标就是在资源加载目录&#xff08;resources&#xff09;下放一个banner.txt文件。这样运行加载的时候就会扫描到这个文件&#xff0c;然后启动的时候就会显…

vue -- 自定义指令钩子函数补充 自定义过滤器filter参数

自定义指令补充 自定义指令通过钩子函数的形式来实现自定义的功能 这里是几个常用的钩子函数以及它的方法&#xff1a; bind&#xff1a;只调用一次&#xff0c;指令第一次绑定到元素时调用&#xff0c;在这里可以进行一次性的初始化设置。 inserted&#xff1a;被绑定元素插…

Docker Nginx 反向代理

最近在系统性梳理网关的知识&#xff0c;其中网关的的功能有一个是代理&#xff0c;正好咱们常用的Nginx也具备次功能&#xff0c;今天正好使用Nginx实现一下反向代理&#xff0c;与后面网关的代理做一个对比&#xff0c;因为我使用的docker安装的Nginx&#xff0c;与直接部署N…

web worker的基本使用案例

文件目录如下 代码按照顺序分别如下 webworker.html <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewpo…

C语言函数: 字符串函数及模拟实现strtok()、strstr()、strerror()

C语言函数&#xff1a; 字符串函数及模拟实现strtok()、strstr()、strerror() strstr()函数: 作用&#xff1a;字符串查找。在一串字符串中&#xff0c;查找另一串字符串是否存在。 形参: str2在str1中寻找。返回值是char*的指针 原理&#xff1a;如果在str1中找到了str2&…

为什么这几年参加PMP考试的人越来越多?

PMP认证从国外引进大陆这么多年了&#xff0c;其火热程度依然不减&#xff0c;我个人认为是取决于市场的运作和“游戏规则”&#xff08;岗位招聘和项目招标需要&#xff09;。PMP含金量不算高&#xff0c;更多的是“敲门砖”作用&#xff0c;项目管理岗位的门槛&#xff0c;当…

MySQL日志审计和分析

审核数据库活动是加强数据库安全性的重要组成部分。这涉及识别漏洞&#xff0c;例如默认或弱登录凭据、过多的用户和组权限以及未修补的数据库。攻击者利用这些漏洞来实现自己的目标&#xff0c;如权限提升、SQL 注入和 DoS 攻击。因此&#xff0c;出于安全性和合规性原因&…

源码分析spring如和对@Component注解进行BeanDefinition注册的

Spring ioc主要职责为依赖进行处理&#xff08;依赖注入、依赖查找&#xff09;、容器以及托管的(java bean、资源配置、事件)资源声明周期管理&#xff1b;在ioc容器启动对元信息进行读取&#xff08;比如xml bean注解等&#xff09;、事件管理、国际化等处理&#xff1b;首先…

SPI读写SD卡速度有多快?

SD卡是一个嵌入式中非常常用的外设&#xff0c;可以用于存储一些大容量的数据。但用单片机读写SD卡速度一般都有限&#xff08;对于高速SD卡&#xff0c;主要是受限于单片机本身的接口速度&#xff09;&#xff0c;在高速、实时数据存储时可能会有影响。但具体速度可以达到多少…

Spark RDD的设计与运行原理

一、Spark RDD概念 一个RDD就是一个分布式对象集合&#xff0c;本质上是一个只读的分区记录集合&#xff0c;每个RDD可以分成多个分区&#xff0c;每个分区就是一个数据集片段&#xff0c;并且一个RDD的不同分区可以被保存到集群中不同的节点上&#xff0c;从而可以在集群中的…

Could not resolve dependencies for project

maven 打包Could not resolve dependencies for project和无效的目标发行版: 1.8 1.maven 打包Could not resolve dependencies for project 最近项目上使用的是idea ide的多模块话&#xff0c;需要模块之间的依赖&#xff0c;比如说系统管理模块依赖授权模块进行认证和授权&a…

聊聊关于分类和分割的损失函数:nn.CrossEntropyLoss()

目录 1. nn.CrossEntropyLoss() 2. 多分类中 nn.CrossEntropyLoss() 的应用 3. 分割中 nn.CrossEntropyLoss() 的应用 3.1 测试文件 3.2 输出可视化 3.3 softmax 3.4 log 3.5 CrossEntropyLoss 1. nn.CrossEntropyLoss() 分类中&#xff0c;经常用 nn.CrossEntropyL…

.NET Core Api使用Folder(文件夹)形式发布并指定监听端口

分为以下几个步骤 1. 先安装SDK及运行环境, 无需安装IIS, 因为他不在IIS上运行 环境下载路径, 我用的是.NET 7.0, 可以根据自己的版本下载: 下载 .NET 7.0 SDK (v7.0.201) - Windows x64 Installer 下载.NET运行环境 下载后安装.直接下一步..安装即可 2. 配置发布设置 (…

Nginx服务优化与防盗链

目录 1.隐藏nginx版本号 1.查看版本号 2.隐藏版本信息 2.修改用户与组 3.缓存时间 4.日志分割 5.连接超时 6.更改进程数 7.网页压缩 8.配置防盗链 1.配置web源主机&#xff08;192.168.156.10 www.lhf.com&#xff09; 2.配置域名映射关系 3.配置盗链主机 &#xff0…

python实现波士顿房价预测---(2)

计算梯度 继续上一篇的内容python实现波士顿房价预测—(1)。 梯度计算公式中引入计算因子12\frac{1}{2}21​&#xff0c;为了计算更加简洁。 L12N∑i1N(yi−zi)2L\frac{1}{2N}\sum_{i1}^{N}(y_i - z_i)^2L2N1​∑i1N​(yi​−zi​)2 其中ziz_izi​是模型对于第i个样本的预测值…

【halcon】轮廓拟合相关函数

涉及函数 edges_sub_pix 寻找边缘 edges_sub_pix (Image, Edges, canny, 1, 10, 20) 后面三个参数&#xff0c;越小&#xff0c;找到的细节越多。这个是对应录波器为canny时。 canny滤波器用的最多。 segment_contours_xld 将连续的轮廓进行分段&#xff0c;按圆弧或者执…

软件测试13

Linux命令 1.pwd&#xff1a;查看当前所在的路径位置 2.ls&#xff1a;查看当前路径下有哪些文件 3.cd&#xff1a;切换路径 4.touch&#xff1a;创建普通文件&#xff0c;可以创建单文件&#xff0c;也可以创建多文件&#xff08;touch a&#xff0c;touch b c&#xff09; 5…

【专项训练】高级搜索

高级搜索,这部分非常烧脑,可略过! 包括:剪枝、双向BFS、启发式搜索! 启发式搜索:优先队列,即优先级搜索! 回溯:分治 + 试错 数独问题,类似八皇后! 36. 有效的数独 https://leetcode.cn/problems/valid-sudoku/description/ class Solution(object

Java【二叉搜索树和哈希表】模拟实现 + 【Map和Set】介绍

文章目录前言一、二叉搜索树1、什么是二叉搜索树2、模拟实现二叉搜索树2.1, 查找2.2, 插入2.3, 删除3、性能分析二、模型三、哈希表1、什么是哈希表1.1, 什么是哈希冲突1.2, 避免, 解决哈希冲突1.2.1, 避免: 调节负载因子1.2.2, 解决1: 闭散列(了解)1.2.3, 解决2: 开散列/哈希桶…

基于卷积神经网络CNN的水果分类预测,卷积神经网络水果等级识别

目录 背影 卷积神经网络CNN的原理 卷积神经网络CNN的定义 卷积神经网络CNN的神经元 卷积神经网络CNN的激活函数 卷积神经网络CNN的传递函数 卷积神经网络CNN水果分类预测 基本结构 主要参数 MATALB代码 结果图 展望 背影 现在生活&#xff0c;为节能减排&#xff0c;减少电能…