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

news2025/1/7 22:43:34

目录😋

任务描述

相关知识

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.coloradmin.cn/o/2272880.html

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

相关文章

杰发科技——使用ATCLinkTool解除读保护

0. 原因 在jlink供电电压不稳定的情况下&#xff0c;概率性出现读保护问题&#xff0c;量产时候可以通过离线烧录工具避免。代码中开了读保护&#xff0c;但是没有通过can/uart/lin/gpio控制等方式进行关闭&#xff0c;导致无法关闭读保护。杰发所有芯片都可以用本方式解除读保…

【pytorch-lightning】架构一览

pytorch-lightning是基于pytorch的一个套壳项目&#xff0c;适配pytorch的版本同步更新速度很快。 它将训练的几个主要流程模块化&#xff0c;减少重复工作&#xff0c;同时让支持分布式训练&#xff0c;不同平台的训练迁移变得更加简单。 官网链接

时空遥感影像智能解译软件(基础版)

一、时空遥感影像智能解译软件&#xff08;基础版&#xff09;简概 “时空遥感影像智能解译软件&#xff08;基础版&#xff09;”&#xff0c;该软件基于Python高级编程语言与PyQt5界面设计框架开发&#xff0c;依赖于sys、os系统库以及OpenCV、GDAL、Numpy、Math、Random、Ma…

Chapter4.3:Implementing a feed forward network with GELU activations

4 Implementing a GPT model from Scratch To Generate Text 4.3 Implementing a feed forward network with GELU activations 本节即将实现子模块&#xff0c;用于transformer block&#xff08;变换器块&#xff09;的一部分。为此&#xff0c;我们需要从激活函数开始。 深…

常见加密算法附JAVA代码案例

1、对称加密算法(AES、DES、3DES) 对称加密算法是指加密和解密采用相同的密钥,是可逆的(即可解密)。 AES加密算法是密码学中的高级加密标准,采用的是对称分组密码体制,密钥长度的最少支持为128。AES加密算法是美国联邦政府采用的区块加密标准,这个标准用来替代原先的…

SwiftUI 撸码常见错误 2 例漫谈

概述 在 SwiftUI 日常撸码过程中&#xff0c;头发尚且还算茂盛的小码农们经常会犯这样那样的错误。虽然犯这些错的原因都很简单&#xff0c;但有时想要快速准确的定位它们却并不容易。 况且这些错误还可能在模拟器和 Xcode 预览&#xff08;Preview&#xff09;表现的行为不甚…

linux系统(ubuntu,uos等)连接鸿蒙next(mate60)设备

以前在linux上是用adb连接&#xff0c;现在升级 到了鸿蒙next&#xff0c;adb就不好用了。得用Hdc来了&#xff0c;在windows上安装了hisuit用的好好的&#xff0c;但是到了linux(ubuntu2204)下载安装了 下载中心 | 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生…

2024年12月HarmonyOS应用开发者高级认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同&#xff0c;作者已于2024年12月15日又更新了一波题库&#xff0c;题库正确率99%&#xff01; 新版…

Anaconda安装(2024最新版)

安装新的anaconda需要卸载干净上一个版本的anaconda&#xff0c;不然可能会在新版本安装过程或者后续使用过程中出错&#xff0c;完全卸载干净anaconda的方法&#xff0c;可以参考我的博客&#xff01; 第一步&#xff1a;下载anaconda安装包 官网&#xff1a;Anaconda | The O…

docker中使用Volume完成数据共享

情景概述 在一个docker中&#xff0c;部署两个MySQL容器&#xff0c;假如它们的数据都存储在自己容器内部的data目录中。这样的存储方式会有以下问题&#xff1a; 1.无法保证两个MySQL容器中的数据同步。 2.容器删除后&#xff0c;数据就会丢失。 基于以上问题&#xff0c;容…

Mac软件介绍之录屏软件Filmage Screen

软件介绍 Filmage Screen 是一款专业的视频录制和编辑软件&#xff0c;适用于 Mac 系统 可以选择4k 60fps&#xff0c;可以选择录制电脑屏幕&#xff0c;摄像头录制&#xff0c;可以选择区域录制。同时也支持&#xff0c;简单的视频剪辑。 可以同时录制电脑麦克风声音 标准…

【Redis经典面试题七】Redis的事务机制是怎样的?

目录 一、Redis的事务机制 二、什么是Redis的Pipeline&#xff1f;和事务有什么区别&#xff1f; 三、Redis的事务和Lua之间有哪些区别&#xff1f; 3.1 原子性保证 3.2 交互次数 3.3 前后依赖 3.4 流程编排 四、为什么Lua脚本可以保证原子性&#xff1f; 五、为什么R…

【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 1. 相关排序和查找算法的原理 2. C 类与成员函数的定义 3. 数组作为类的成员变量的处理 4. 函数参数传递与返回值处理 编程要求 测试说明 通关代码 测试结果 任务描述 本关任务&#xff1a; 将直接插入排序、直接选择排序、冒泡…

[开源]自动化定位建图系统

系统状态机&#xff1a; 效果展示&#xff1a; 1、 机器人建图定位系统-基础重定位&#xff0c;定位功能演示 2、 机器人建图定位系统-增量地图构建&#xff0c;手动回环检测演示 3、敬请期待… 开源链接&#xff1a; 1、多传感器融合里程计 https://gitee.com/li-wenhao-lw…

简单的jmeter数据请求学习

简单的jmeter数据请求学习 1.需求 我们的流程服务由原来的workflow-server调用wfms进行了优化&#xff0c;将wfms服务操作并入了workflow-server中&#xff0c;去除了原来的webservice服务调用形式&#xff0c;增加了并发处理&#xff0c;现在想测试模拟一下&#xff0c;在一…

conda/pip基本常用命令理解与整理

最近配置了两轮pytorch环境&#xff0c;由于要频繁用到各种conda和pip命令&#xff0c;所以再此整理一下。 文章目录 前言&#xff1a;conda虚拟环境总结与解读Conda和pip的理解区别和联系命令格式 conda环境命令查看创建和删除导出与导入激活和退出 包管理命令安装和删除文件批…

Maven 详细配置:Maven settings 配置文件的详细说明

Maven settings 配置文件是 Maven 环境的重要组成部分&#xff0c;它用于定义用户特定的配置信息和全局设置&#xff0c;例如本地仓库路径、远程仓库镜像、代理服务器以及认证信息等。settings 文件分为全局配置文件&#xff08;settings.xml&#xff09;和用户配置文件&#x…

Unity-Mirror网络框架-从入门到精通之Chat示例

文章目录 前言Chat聊天室Authentication授权ChatAuthenticatorChat示例中的授权流程聊天Chat最后 前言 在现代游戏开发中&#xff0c;网络功能日益成为提升游戏体验的关键组成部分。Mirror是一个用于Unity的开源网络框架&#xff0c;专为多人游戏开发设计。它使得开发者能够轻…

复杂园区网基本分支的构建

目录 1、各主机进行网络配置。2、交换机配置。3、配置路由交换&#xff0c;进行测试。4、配置路由器接口和静态路由&#xff0c;进行测试。5、最后测试任意两台主机通信情况 模拟环境链接 拓扑结构 说明&#xff1a; VLAN标签在上面的一定是GigabitEthernet接口的&#xff0c…

这是什么操作?强制迁移?GitLab 停止中国区用户访问

大家好&#xff0c;我是鸭鸭&#xff01; 全球知名代码托管平台 GitLab 发布通告&#xff0c;宣布不再为位于中国大陆、香港及澳门地区的用户提供访问服务&#xff0c;并且“贴心”建议&#xff0c;可以访问极狐 GitLab。 极狐 GitLab 是一家中外合资公司&#xff0c;宣称获得…