C++面向对象与多态

实现多态

本文的目的是为了实现C++的多态调用,为此,我们需要先了解一些知识,后续来一个具体实现。

虚函数与纯虚函数的区别

在C++中,虚函数(virtual function)和纯虚函数(pure virtual function)是面向对象编程中实现多态性的关键概念。它们之间的主要区别在于声明、实现和使用方面。下面详细解释这两种虚函数的特点和用途:

虚函数(Virtual Function)

虚函数是在基类中声明的,其主要目的是为了在派生类中可以被重写,从而实现运行时的多态性。当一个对象指针或引用指向派生类对象时,通过该指针或引用调用虚函数,会调用到派生类中重写的那个函数,而不是基类中的函数。这是C++多态的基础。

声明:

虚函数的声明使用virtual关键字前缀,例如:

class Base {
public:
    virtual void func() { /* ... */ }
};
实现:

虚函数在基类中可以有默认实现,派生类可以选择性地重写这个函数。

作用:
  • 实现运行时多态性。
  • 可以在基类中提供默认的行为,派生类按需覆盖。
纯虚函数(Pure Virtual Function)

纯虚函数是一种特殊的虚函数,它在基类中没有实现,必须在派生类中被实现。纯虚函数的存在是为了强制派生类必须提供一个具体的实现,否则编译器将报错。

声明:

纯虚函数的声明同样使用virtual关键字,但是函数体用= 0表示,例如:

class Base {
public:
    virtual void func() = 0; // 纯虚函数
};
实现:

纯虚函数在基类中没有实现,派生类必须提供实现,否则派生类也将变成抽象类,不能实例化。

作用:
  • 强制派生类实现某个方法,确保所有派生类都有相同的行为接口。
  • 基类带有纯虚函数时,基类就变成了抽象类,不能被实例化,只能作为其他类的基类。
总结
  • 虚函数允许在基类中有默认实现,可以被派生类重写或保留原样,主要用于实现多态性。
  • 纯虚函数在基类中无实现,强制派生类必须实现,常用于定义接口,确保所有派生类都提供一致的行为。

通过使用虚函数和纯虚函数,C++支持了面向对象编程中的封装、继承和多态特性,提高了代码的复用性和灵活性。

好了,前面这个是前提,就是如何定义一个抽象类,子类实现具体代码的知识点了,现在来写一个抽象类:

动物抽象类

Animal.hpp

#pragma once

//动物抽象类
class Animal {
 public:
  virtual ~Animal() {}
  virtual std::string run() const = 0;  // 纯虚函数
};
子类

Cat.hpp

#pragma once
#include <iostream>
#include "Animal.hpp"

//实现类猫
class Cat : public Animal {
public:
	Cat() {
		std::cout << "Cat 构造";
	}
	std::string run() const override {
		return "喵喵喵";
	}
};

Dog.hpp

#pragma once
#include <iostream>
#include "Animal.hpp"

//实现类狗
class Dog : public Animal {
public:
	Dog() {
		std::cout << "Dog 构造";
	}
	std::string run() const override {
		return "汪汪汪";
	}
};

好了,类有了,现在就是实现多态的时候了,弄一个动物工厂,用来创建需要的类
AnimalFactory2.hpp

#pragma once
#include <memory>

#include "Animal.hpp"
#include "Dog.hpp"
#include "Cat.hpp"

//动物工厂
class AnimalFactory2 {
public:
    static std::unique_ptr<Animal> createAnimal(const std::string& animalType) {

        if (animalType == "Cat") {
            return std::make_unique<Cat>();
        }

        if (animalType == "Dog") {
            return std::make_unique<Dog>();
        }

        throw std::runtime_error("Invalid animal type");
    }
};

使用方式如下:

    try
    {
        auto dog = AnimalFactory2::createAnimal("Dog");
        std::cout << dog->run() << std::endl;

        auto cat = AnimalFactory2::createAnimal("Cat");
        std::cout << cat->run() << std::endl;
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

这里就实现了面向对象的多态了,简单有效,但是有点不足的是,扩展性,新增一种动物需要修改工厂,我们来改改,换一种工厂
AnimalFactory.hpp

#pragma once
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>

#include "Animal.hpp"

//动物工厂
class AnimalFactory {
private:
    static std::map<std::string, std::function<std::unique_ptr<Animal>()>> animalCreators;
public:
    static void registerAnimal(const std::string& animalType,
        std::function<std::unique_ptr<Animal>()> creator) {
        animalCreators[animalType] = creator;
    }
    //创建函数,通过映射查找并创建相应的对象
    static std::unique_ptr<Animal> createAnimal(const std::string& animalType) {
        auto it = animalCreators.find(animalType);
        if (it != animalCreators.end()) {
            return it->second();
        }
        else {
            throw std::runtime_error("Invalid animal type");
        }
    }
};

// 初始化静态成员
std::map<std::string, std::function<std::unique_ptr<Animal>()>> AnimalFactory::animalCreators;

利用 std::map 和 std::function ,lambda 实现一种字符串与对象的映射关系,使用方式如下:

    AnimalFactory::registerAnimal("Dog", []() { return std::make_unique<Dog>(); });
    AnimalFactory::registerAnimal("Cat", []() { return std::make_unique<Cat>(); });

    try {
        auto dog = AnimalFactory::createAnimal("Dog");
        std::cout << dog->run() << std::endl;

        auto cat = AnimalFactory::createAnimal("Cat");
        std::cout << cat->run() << std::endl;
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }

这种方式,实现略显复杂,但是扩展性好,对于需要实现的类,注册到工厂里,后续使用方便。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何选择合适的PCB表面处理工艺?

在PCB制造中应用PCB表面处理至关重要&#xff0c;以保护铜迹线不受氧化和环境污染物的侵蚀&#xff0c;这些污染物会降低性能。这些PCB表面处理可以防止水分、灰尘、化学物质和极端温度的侵入&#xff0c;防止PCB材料的腐蚀。它们还有助于在组装过程中有效焊接和粘合&#xff0…

240707_昇思学习打卡-Day19-基于MindSpore通过GPT实现情感分类

240707_昇思学习打卡-Day19-基于MindSpore通过GPT实现情感分类 今天基于GPT实现一个情感分类的功能&#xff0c;假设已经安装好了MindSpore环境。 # 该案例在 mindnlp 0.3.1 版本完成适配&#xff0c;如果发现案例跑不通&#xff0c;可以指定mindnlp版本&#xff0c;执行!pip…

Git 查看、新建、删除、切换分支

Git 是一个版本控制系统&#xff0c;软件开发者用它来跟踪应用程序的变化并进行项目协作。 分支的诞生便于开发人员在彼此独立的环境中进行开发工作。主分支&#xff08;通常是 main 或 master&#xff09;可以保持稳定&#xff0c;而新的功能或修复可以在单独的分支中进行开发…

STM32智能无人机控制系统教程

目录 引言环境准备智能无人机控制系统基础代码实现&#xff1a;实现智能无人机控制系统 4.1 数据采集模块 4.2 数据处理与飞行控制 4.3 通信与导航系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;无人机应用与优化问题解决方案与优化收尾与总结 1. 引言 智能无人机控…

AI工具杂谈

AI是在帮助开发者还是取代他们&#xff1f; 在软件开发领域&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;正在改变开发者的工作方式。无论是代码生成、错误检测还是自动化测试&#xff0c;AI工具正在成为开发者的得力助手。然而&#xff0c;这也引发了对开发者职业…

哪个牌子的护眼大路灯质量好呢?性价比高的五款护眼大路灯分享

护眼大路灯可以说是是每个有娃家庭必不可少的照明神器。但面对市场上琳琅满目的护眼落地灯品牌和型号&#xff0c;很多消费者在选购时都会犯难&#xff1a;究竟哪个牌子的护眼大路灯质量好呢&#xff1f;哪个性价比高呢&#xff1f;本文将根据市场反馈以及性价比等各方面&#…

Table 表格--分页序号自增

代码&#xff1a; import { Space, Table, Tag } from antd; import type { ColumnsType } from antd/es/table; import React, { useState } from react;interface DataType {key: string;name: string;age: number;address: string;tags: string[]; }const data: DataType[]…

6K star! 部署本地运行LLM的AI助手,零基础入门到精通超详细

AI套壳千千万万&#xff0c;你最喜欢哪一款&#xff1f;现在各种ChatGPT替代品层出不穷&#xff0c;但是大部分都是使用OpenAI的API&#xff0c;也就说离不开网络。 今天我们推荐的开源项目它就是要帮你100%在本地运行大模型&#xff0c;进而构建一个属于自己的ChatGPT&#x…

使用 Docker 部署一个文档管理系统,让宝贵文档不在丢失!

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 BookStack 是一个开源的文档管理系统,非常适合用来创建和组织文档。 通过 Docker,我们可以轻松地将 BookStack 部署到本地或服务器上。 本文将详细介绍如何使用 Docker 搭建 BookStack。 项目预览 登录页面

element-plus 的form表单组件之el-radio(单选按钮组件)

单选按钮组件适用于同一组类型的选项只能互斥选择的场景&#xff0c;就是支持单选。单选组件包含以下3个组件 组件名作用el-radio-group单选组组件&#xff0c;子元素可以是el-radio或el-radio-button&#xff0c;v-mode绑定单选组的响应式属性el-radio单选组件&#xff0c;la…

如何确保工业展厅设计既专业又吸引?三原则详解!

工业是民族发展的基石&#xff0c;它为我们带来了无数的便利和进步&#xff0c;而为了让更多人了解这个至关重要的产业&#xff0c;以及其背后的技术和产品&#xff0c;许多工业性质的企业都致力于通过互动投影、虚拟现实、全息投影等多媒体技术&#xff0c;来打造独具特色的工…

起底:Three.js和Cesium.js,二者异同点,好比全科和专科.

Three.js和Cesium.js是两个常用的webGL引擎&#xff0c;很多小伙伴容易把它们搞混淆了&#xff0c;今天威斯数据来详细介绍一下&#xff0c;他们的起源、不同点和共同点&#xff0c;阅读后你就发现二者就像全科医院和专科医院的关系&#xff0c;很好识别。 一、二者的起源 Th…

LiveNVR监控流媒体Onvif/RTSP用户手册-录像回看:录像通道、查看录像、设备录像、云端录像查、时间轴视图、录像分享

LiveNVR监控流媒体Onvif/RTSP用户手册-录像回看:录像通道、查看录像、设备录像、云端录像查、时间轴视图、录像分享 1、录像回看1.1、查看录像1.1.1、时间轴视图1.1.2、列表视图 2、如何分享时间轴录像回看&#xff1f;3、iframe集成示例4、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服…

RabbitMQ(集群相关部署)

RabbitMQ 集群部署 环境准备&#xff1a;阿里云centos8 服务器&#xff0c;3台服务器&#xff0c;分别进行安装&#xff1b; 下载Erlang Erlang和RabbitMQ版本对照&#xff1a;https://www.rabbitmq.com/which-erlang.html 创建yum库配置文件 vim /etc/yum.repos.d/rabbi…

Soong 构建系统

背景 Soong 构建系统在Android 7.0开始引入&#xff0c;目的是取代Make。它利用Kati GNU Make 和Ninja构建系统组件来构建Android Soong是用Go语言写的&#xff0c;go环境在prebuilts/go环境下&#xff0c;Soong在编译时&#xff0c;解析bp文件&#xff0c;转化成Ninja文件&am…

互联网留给网站建设的,也就一个门缝了,抓紧往高端进发吧。

高端定制网站具有以下价值&#xff1a; 独特性&#xff1a;高端定制网站能够根据企业的品牌形象和定位进行设计&#xff0c;呈现独特的风格和用户体验。这有助于提升企业的品牌形象和差异化竞争力&#xff0c;使企业在竞争激烈的市场中脱颖而出。用户体验&#xff1a;高端定制…

vue-使用Worker实现多标签页共享一个WebSocket

文章目录 前言一、SharedWorker 是什么SharedWorker 是什么SharedWorker 的使用方式SharedWorker 标识与独占 二、Demo使用三、使用SharedWorker实现WebSocket共享 前言 最近有一个需求&#xff0c;需要实现用户系统消息时时提醒功能。第一时间就是想用WebSocket进行长连接。但…

14-47 剑和诗人21 - 2024年如何打造AI创业公司

​​​​​ 2024 年&#xff0c;随着人工智能继续快速发展并融入几乎所有行业&#xff0c;创建一家人工智能初创公司将带来巨大的机遇。然而&#xff0c;在吸引资金、招聘人才、开发专有技术以及将产品推向市场方面&#xff0c;人工智能初创公司也面临着相当大的挑战。 让我来…

下一代 CLI 工具,使用Go语言用于构建令人惊叹的网络应用程序

大家好&#xff0c;今天给大家分享一个创新的命令行工具Gowebly CLI&#xff0c;它专注于使用Go语言来快速构建现代Web应用程序。 Gowebly CLI 是一款免费开源软件&#xff0c;有助于在后端使用 Go、在前端使用 htmx 和 hyperscript 以及最流行的 CSS 框架轻松构建令人惊叹的 W…

Maven Nexus3 私服搭建、配置、项目发布指南

maven nexus私服搭建 访问nexus3官方镜像库,选择需要的版本下载:Docker Nexus docker pull sonatype/nexus3:3.49.0 创建数据目录并赋权 sudo mkdir /nexus-data && sudo chown -R 200 /nexus-data 运行(数据目录选择硬盘大的卷进行挂载) docker run -d -p 808…