【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】

目录😋

任务描述

相关知识

1. 纯虚函数

一、特点

二、使用场景

三、作用

四、注意事项

五、相关概念对比

2. 抽象类的使用

一、定义与概念

二、使用场景

编程要求

测试说明

通关代码

测试结果


任务描述

本关任务:设计一个矩形类、一个圆形类和一个图形基类,计算并输出相应图形面积。

相关知识

为了完成本关任务,你需要掌握:

  1. 纯虚函数
  2. 抽象类的使用

1. 纯虚函数

一、特点
  1. 函数声明形式
    纯虚函数在声明时有其特定的语法形式,如 virtual 函数类型 函数名(参数列表) = 0;。以之前提到的 Base 类中的 virtual void Func() = 0; 为例,virtual 关键字表明这是一个虚函数,而最后的 = 0 则明确指出它是纯虚函数,意味着该函数在当前类(这里是 Base 类)中不提供具体的函数实现(也就是没有函数体),仅预留函数名和参数列表等信息,等待派生类去完善其具体功能。
  2. 不可直接调用
    由于纯虚函数本身没有函数体,在基类层面它是不能被直接调用的。如果尝试在基类对象上调用纯虚函数,编译器会报错,因为它没有实际可执行的代码逻辑与之对应。例如:
    Base baseObj;
    baseObj.Func();  // 这样的调用会导致编译错误,因为Base类中Func是纯虚函数,无函数体
  3. 派生类要求
    纯虚函数必须在派生类中进行定义,否则该虚函数在派生类中依然保持为纯虚函数状态。当派生类实现了这个纯虚函数后,才能通过派生类的对象调用这个函数,且调用时执行的是派生类中定义的函数逻辑。例如:
    class Derived : public Base {
    public:void Func() override {// 在这里定义Func函数在Derived类中的具体实现逻辑std::cout << "This is the implementation of Func in Derived class." << std::endl;}
    };Derived derivedObj;
    derivedObj.Func();  // 调用Derived类中实现的Func函数,输出相应内容,编译通过
二、使用场景
  1. 实现多态性
    纯虚函数是实现面向对象编程中多态性的重要手段之一。基类定义了一系列纯虚函数作为接口,不同的派生类根据自身的特点和需求去具体实现这些函数,这样就可以通过基类指针或引用指向不同的派生类对象,并调用这些虚函数时,执行不同派生类中对应的函数实现,呈现出多态的行为。例如,设计一个图形类作为基类,有 draw() 这样的纯虚函数,然后派生出 Circle(圆形)、Rectangle(矩形)等具体图形类,每个派生类各自实现 draw() 函数来绘制对应的图形,通过基类指针可以统一操作不同图形对象的绘制操作,代码可能如下:
    class Shape {
    public:virtual void draw() = 0;
    };class Circle : public Shape {
    public:void draw() override {std::cout << "Drawing a circle." << std::endl;}
    };class Rectangle : public Shape {
    public:void draw() override {std::cout << "Drawing a rectangle." << std::endl;}
    };int main() {Shape* shapePtr1 = new Circle();Shape* shapePtr2 = new Rectangle();shapePtr1->draw();shapePtr2->draw();delete shapePtr1;delete shapePtr2;return 0;
    }

    在上述代码中,通过基类 Shape 的指针指向不同派生类对象,调用 draw 函数时,根据对象实际类型执行相应派生类中定义的绘制逻辑,体现了多态性。

  2.  定义抽象类
    含有纯虚函数的类被称为抽象类,抽象类不能实例化对象(像前面例子中直接创建 Base 类对象就会报错),它更多的是作为一种抽象的概念和接口规范存在,用于为派生类提供统一的函数接口框架,引导派生类去实现特定的功能,使得整个类层次结构在设计上更加清晰、规范,便于代码的扩展和维护。例如在设计一个动物类层次结构时,动物都有 makeSound() 这个行为,但不同动物发声方式不同,所以可以在基类 Animal 中定义 virtual void makeSound() = 0; 纯虚函数,然后各种具体动物类(如 DogCat 等)去实现这个函数来体现各自独特的叫声。

三、作用
  1. 接口规范作用
    纯虚函数在基类中定义了一个统一的函数接口,明确告知派生类需要实现哪些功能,保证了派生类在实现相关功能时有一致的函数签名(函数名、参数列表、返回类型等方面符合基类定义),有助于提高代码的可读性和可维护性。不同的开发人员在编写派生类时,能清楚知道需要遵循的接口规范,避免随意编写函数而导致代码逻辑混乱。
  2. 代码扩展性提升
    当需要在已有类层次结构基础上添加新的派生类时,只要按照基类中纯虚函数定义的接口去实现相应功能即可,不需要对基类或者其他已有派生类做大量修改。例如,在前面图形类的例子中,如果后续要添加一个 Triangle(三角形)类,只需从 Shape 类派生,然后实现 draw 函数来绘制三角形就行,原有操作图形绘制的代码(通过基类指针调用 draw 函数的部分)无需改动就能适用于新的三角形图形对象,方便了代码的扩展和功能的丰富。
四、注意事项
  1. 继承关系中的纯虚函数处理
    在多层继承结构中,如果中间层派生类没有对基类的纯虚函数进行定义,那么这个纯虚函数依然会传递下去,在该中间层派生类的派生类中依然需要进行定义才能实例化对象。例如:
    class Base {
    public:virtual void func() = 0;
    };class Intermediate : public Base {
    // 这里没有对func函数进行定义,func在Intermediate类中依然是纯虚函数
    };class Derived : public Intermediate {
    public:void func() override {// 在这里定义func函数实现,使得Derived类可以实例化对象}
    };
  2. 函数签名一致性
    派生类在定义纯虚函数时,必须保证函数签名(包括函数名、参数列表、返回类型,返回类型协变情况除外)与基类中纯虚函数的定义严格一致,否则编译器会认为是在重新定义一个新的函数,而不是实现基类中的纯虚函数,导致编译错误。例如:
    class Base {
    public:virtual int calculate(int num) = 0;
    };class Derived : public Base {
    public:double calculate(int num) override {  // 返回类型不一致,会导致编译错误return 0.0;}
    };
五、相关概念对比
  1. 虚函数与纯虚函数
    虚函数可以在基类中有具体的函数体实现,派生类可以选择重写(override)它来实现多态性,也可以不重写而直接继承基类的函数实现。而纯虚函数在基类中没有函数体,必须由派生类去定义实现,主要用于定义抽象类和接口规范,引导派生类进行特定功能的实现,以此来实现多态等面向对象编程特性。
  2. 抽象类与具体类
    含有纯虚函数的类就是抽象类,它不能被实例化,侧重于提供抽象的接口和概念框架。而具体类是可以实例化对象的类,通常是在抽象类基础上,通过实现其纯虚函数等方式,完善了具体功能,从而成为能够创建实际对象并使用的类,比如前面例子中的 CircleRectangle 等就是具体类,它们基于抽象的 Shape 类实现了具体绘制图形的功能,进而可以创建相应图形对象进行操作。

2. 抽象类的使用

一、定义与概念

    抽象类是一种不能被实例化的类,它通常包含一个或多个纯虚函数。纯虚函数是在声明时被初始化为 0 的虚函数,例如:virtual void func() = 0;。抽象类主要用于为派生类提供一个通用的接口规范,定义一系列的行为和属性,但把具体的实现细节留给派生类。
 

二、使用场景

 1、多态性实现

        假设要开发一个图形绘制程序,有多种图形如圆形、矩形等。可以先定义一个抽象类Shape作为基类,其中包含一个纯虚函数draw():

class Shape {
public:virtual void draw() = 0;
};

然后派生出具体的图形类,如CircleRectangle,它们分别实现draw()函数来绘制自己的形状:

class Circle : public Shape {
public:void draw() override {// 绘制圆形的具体代码,比如使用绘图库来绘制cout << "Drawing a circle." << endl;}
};
class Rectangle : public Shape {
public:void draw() override {// 绘制矩形的具体代码cout << "Drawing a rectangle." << endl;}
};

这样,通过基类指针或引用,可以方便地调用不同派生类的draw()函数,实现多态性。例如:

Shape* shapePtr;
shapePtr = new Circle();
shapePtr->draw();
delete shapePtr;
shapePtr = new Rectangle();
shapePtr->draw();
delete shapePtr;

2、代码结构规范:

        在大型项目中,抽象类可以用于规范代码结构。比如在一个游戏开发项目中,有不同类型的角色,如战士、法师等。可以定义一个抽象类Character,其中包含纯虚函数attack()move()等:

class Character {
public:virtual void attack() = 0;virtual void move() = 0;
};

战士类Warrior和法师类Mage等派生类实现这些纯虚函数来定义自己的攻击和移动方式。这种方式使得不同角色的行为定义有了统一的规范,便于代码的维护和扩展。例如:

class Warrior : public Character {
public:void attack() override {cout << "Warrior attacks with sword." << endl;}void move() override {cout << "Warrior runs quickly." << endl;}
};
class Mage : public Character {
public:void attack() override {cout << "Mage casts a spell." << endl;}void move() override {cout << "Mage teleports." << endl;}
};

3、继承关系中的注意事项

  • 纯虚函数的继承:如果基类是抽象类,派生类没有实现基类中的所有纯虚函数,那么派生类仍然是抽象类。例如:
    class Base {
    public:virtual void func1() = 0;virtual void func2() = 0;
    };
    class Derived : public Base {
    public:void func1() override {// 实现func1}
    };

    在这个例子中,Derived类仍然是抽象类,因为它没有实现func2,所以不能实例化Derived类的对象。

  • 函数签名一致性:派生类在实现抽象类中的纯虚函数时,要保证函数签名(包括函数名、参数类型、返回类型等)与抽象类中的定义一致。只有满足这个条件,才能正确地实现多态性。例如,如果抽象类中有一个纯虚函数virtual int calculate(double num) = 0;,派生类中实现的函数应该具有相同的函数名、参数类型和返回类型,如int calculate(double num) override {... }

4、与具体类的对比

        具体类是可以直接实例化对象的类,它实现了所有必要的功能。而抽象类侧重于定义接口和行为规范,不能直接创建对象。抽象类为具体类提供了一个模板,具体类通过继承抽象类并实现其纯虚函数来具体化抽象类所定义的概念。例如,在前面图形的例子中,CircleRectangle是具体类,可以创建它们的对象来表示具体的图形并进行绘制操作,而Shape是抽象类,用于规定所有图形类都应该有draw()这个行为,但本身不能用来创建一个没有具体形状的图形对象。


编程要求

在右侧编辑器中的Begin-End之间补充代码,设计图像基类、矩形类和圆形类三个类,函数成员变量据情况自己拟定,其他要求如下:

  • 图形类(Shape)

    • 纯虚函数:void PrintArea(),用于输出当前图形的面积。
  • 矩形类(Rectangle)

    • 继承关系:继承 Shape 类,并且重写 PrintArea 函数,输出矩形的面积,输出格式为:矩形面积 = width*height。
    • 带参构造函数:Rectangle(float w,float h),这两个参数分别赋值给成员变量的宽、高。
  • 圆形类(Circle)

    • 继承关系:继承 Shape 类,并且重写 PrintArea 函数,输出圆形的面积,输出格式为:圆形面积 = radio * radio * 3.14。
    • 带参构造函数:Circle(float r),参数 r 代表圆的半径。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确数值,只有所有数据全部计算正确才能通过测试:

测试输入:

10 2.5

预期输出:

矩形面积 = 20
圆形面积 = 314

测试输入:

2 2.5

预期输出:

矩形面积 = 4
圆形面积 = 12.56

开始你的任务吧,祝你成功!


通关代码

#include <iostream>
using namespace std;/********* Begin *********/
class Shape
{//基类的声明public:virtual void PrintArea() = 0;};class Rectangle : public Shape
{//矩形类的声明public:void PrintArea()override;float width;float height;Rectangle(float w,float h);
};
//矩形类的定义
void Rectangle::PrintArea(){cout<<"矩形面积 = "<<width * height<<endl;
}
Rectangle::Rectangle(float w,float h){width = w;height = h;
}
class Circle : public Shape
{//圆形类的声明public:void PrintArea()override;float radio;Circle(float r);
};
//圆形类的定义
void Circle::PrintArea(){cout <<"圆形面积 = "<<radio * radio *3.14<<endl;
}
Circle::Circle(float r){radio = r;
}
/********* End *********/

测试结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32 拓展 电源控制

目录 电源控制 电源框图 VDDA供电区域 VDD供电区域 1.8V低电压区域 后备供电区域 电压调节器 上电复位和掉电复位 可编程电压检测器(PVD) 低功耗 睡眠模式(只有CUP(老板)睡眠) 进入睡眠模式 退出睡眠模式 停机(停止)模式(只留核心区域(上班)) 进入停…

c# CodeFirst生成表字段加注释

前置&#xff1a;ORM框架工具使用的FreeSql 背景&#xff1a;开发环境中运行接口&#xff0c;所有的表字段以及备注会自动加上&#xff0c;但是在测试环境时运行就只生成了表&#xff0c;没有把每个字段的注释加上 问题检查&#xff1a; FreeSql CodeFirst 支持将 c# 代码内的注…

Python连接和操作Elasticsearch详细指南

Python连接和操作Elasticsearch详细指南 一、服务器端配置1. 修改 Elasticsearch 配置文件2. 开放防火墙端口 二、本地 Python 连接 Elasticsearch1. 连接 Elasticsearch2. 索引操作3. 文档操作4. 搜索内容5. 聚合查询6. 批量操作 三、注意事项四、故障排除结论 Elasticsearch …

五个不同类型的数据库安装

一、 官方首页下载 打开 MySQL 官方首页&#xff0c;链接为&#xff1a; MySQL 进去社区后选择合适的版本进行安装 安装细节 依图一路next 点击finish结束安装 二、 在线YUM仓库 将该安装包的下载链接在 Linux 操作系统中按照以下命令直接进行下载 三、 二进制本地 通过该链接…

用户界面软件01

Jens Coldewey 著&#xff0c;Tom.X 译 本文中的模式语言逐步深入地探讨用户界面架构的设计&#xff0c;它基于人机工程学&#xff0c;足以形成一套完整的体系。如果你对这方面有兴趣&#xff0c;请参考[Tog92]&#xff0c;[Coo95]和[Col95]。 本文不讨论用户界面的布局&…

Android 性能优化:内存优化(实践篇)

1. 前言 前一篇文章Android性能优化&#xff1a;内存优化 &#xff08;思路篇&#xff09; 大概梳理了Android 内存原理和优化的必要性及应该如何优化&#xff0c;输出了一套短期和长期内存优化治理的SOP方案。 那么这一篇文章就总结下我最近在做内存优化如何实践的&#xff0…

stm32第一次烧录或者上电运行卡死问题分析

问题描述 单片机烧录代码&#xff08;刚上电&#xff09;无法立即运行&#xff0c;必须要复位一次或多次才能运行&#xff1b;跟踪调试会进入HardFault_Handler中断。 问题分析 烧录配置如下图&#xff0c;首先排除配置问题那么该问题就比较让人头大了&#xff0c;理论上&am…

Unity中 Xlua使用整理(一)

1.安装: 从GitHub上下载Xlua源码 Tencent/xLua: xLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc. (github.com) 下载Xlua压缩包&#xff0c;并解压将Aseet文件夹中的Xlua和Plugins文件夹复制到Unit…

git理解记录

文章目录 1. 背景2. 基本概念3. 日常工作流程4. 其他常见操作4.1 merge合并操作4.2 tag打标签操作4.3 remoute远程操作4.4 撤销修改 git理解记录 1. 背景 git作为分布式版本控制系统&#xff0c;开源且免费&#xff0c;相比svn集中式版本控制系统存在速度快(HEAD指针指向某次co…

js复制数据到剪切板

方法一&#xff1a; 在下面方法传入你想要复制的字符 &#xff0c;直接调用该方法就好 export function copyText(text: string) {if (navigator.clipboard) {// clipboard api 复制navigator.clipboard.writeText(text)} else {const textarea document.createElement(text…

服务器Ubuntu22.04系统下 ollama的详细部署安装和搭配open_webui使用

服务器Ubuntu22.04系统下 ollama的详细部署安装和搭配open_webui使用 一、ubuntu和docker基本环境配置1.更新包列表&#xff1a;2. 安装docker依赖3. 添加docker密钥4.添加阿里云docker软件源5.安装docker6.安装完成docker测试7. docker配置国内镜像源 二、安装英伟达显卡驱动1…

LInux单机安装Redis

1. 安装gee工具包 由于Redis是基于c语言编写的所以安装的时候需要先安装gee以及gcc的依赖,yum云用不了可以看一下这个 linux 替换yum源镜像_更换yum镜像源-CSDN博客 yum install -y gcc tcl 2. 添加redis的压缩包 3. 上传到Linux 上传到 /usr/local/src 目录、这个目录一般用于…

西门子200smart存储卡作用

最近维修设备时&#xff0c;遇到一个问题&#xff0c;设备PLC是200smart SR20,PLC程序需要修改某个程序段&#xff0c;由于手里没有源程序&#xff0c;联系厂家后&#xff0c;厂家发了一段程序&#xff0c;后缀是.s7s。通过查询官网资料&#xff0c;其中S7_JOB.S7S为脚本任务&a…

QT上实现SVM进行数据分类

针对不了解SVM的原理的同学强推下面这个课程&#xff1a; 6.机器学习课程&#xff08;六&#xff09;支持向量机&#xff08;线性模型&#xff09;问题_哔哩哔哩_bilibili 一、QT实现SVM的方法 1.调用SVM的C语言库&#xff1a;麻烦&#xff0c;要专门去找库&#xff0c;cmak…

【C++】字符串与字符数|组操作详解:strcpy 和 strcat 的使用与解析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;一、字符串数组的基本操作&#x1f4af;二、strcpy 的用法详解1. strcpy 的功能与原型2. 使用示例与代码演示3. 注意事项4. 扩展&#xff1a;为什么不能直接用 &#xff1f…

GWAS数据和软件下载

这部分主要是数据获取,以及软件配置方法。 一、配套数据和代码 数据和代码目前在不断的更新,最新的教程可以私信,我通过后手动发送最新版的pdf和数据代码。发送的压缩包,有电子版的pdf和数据下载链接,里面是最新的百度网盘的地址,下载到本地即可。然后根据pdf教程,结合配套的…

Vue笔记-001-声明式渲染

https://cn.vuejs.org/tutorial/#step-2https://cn.vuejs.org/tutorial/#step-2 Vue 单文件组件 (Single-File Component&#xff0c;缩写为 SFC) 单文件组件是一种可复用的代码组织形式&#xff0c;它将从属于同一个组件的 HTML、CSS 和 JavaScript 封装在使用 .vue 后缀的文件…

Scala_【5】函数式编程

第五章 函数式编程函数和方法的区别函数声明函数参数可变参数参数默认值 函数至简原则匿名函数高阶函数函数作为值传递函数作为参数传递函数作为返回值 函数闭包&柯里化函数递归控制抽象惰性函数友情链接 函数式编程 面向对象编程 解决问题时&#xff0c;分解对象&#xff…

(六)优化 ChatGPT 交互:任务式 Prompt 的力量

&#x1f4e2;&#x1f4e2;&#x1f4e2; 大家好&#xff0c;我是云楼Yunlord&#xff0c;CSDN博客之星人工智能领域前三名&#xff0c;多年人工智能学习工作经验&#xff0c;一位兴趣稀奇古怪的【人工智能领域博主】&#xff01;&#xff01;&#xff01;&#x1f61c;&#…

HarmonyOS-面试资料

1. HarmonyOS-面试资料 1.1. HarmonyOS 优点、特点 1.1.1. 优点 &#xff08;1&#xff09;在国家方面&#xff0c;是国产的系统&#xff0c;受国家支持不会有限制的情况。   &#xff08;2&#xff09;设备互连18N(1:手机 8&#xff1a;平板、PC、vr设备、可穿戴设备、智慧…