C++中的接口有什么用
2023年12月13日,周三上午
今天上午在适配器模式,我发现如果想真正理解适配器模式,就必须学会使用C++中的接口,就必须明白为什么要在C++中使用接口,所以重新学习了一下C++中的接口
目录
- C++中的接口有什么用
- 用代码说明“实现多态性”
- 用代码说明“隐藏实现细节”
- 用代码说明“实现代码解耦“
C++中的接口有什么用
在C++中,虽然没有像其他编程语言(如Java和C#)中的明确接口(interface)概念,但可以使用抽象类来实现类似的功能。
接口在软件开发中起到了以下几个重要的作用:
-
实现多态性:接口提供了一种定义规范的方式,可以通过多态性实现对象的替换和统一的调用方式。通过接口,不同的类可以实现相同的接口,并以统一的方式进行调用。
-
隐藏实现细节:接口定义了一组可供外部使用的方法,同时隐藏了具体实现的细节。这样,使用接口的代码只需要关注接口定义的方法,而不需要了解具体的实现细节。
-
实现代码解耦:通过接口,将不同的部分分离开来,使得代码的耦合度降低。接口作为一个中间层,将不同的模块解耦,使得代码更加灵活和可维护。
-
提高代码的可扩展性:通过接口,可以为系统提供一种扩展的方式。当需要增加新的功能时,只需要实现相应的接口并符合接口定义的规范,而无需修改原有的代码。
用代码说明“实现多态性”
#include <iostream>// 定义接口(抽象类)
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* shape1 = new Circle();Shape* shape2 = new Rectangle();shape1->draw(); // 调用Circle类的draw方法shape2->draw(); // 调用Rectangle类的draw方法delete shape1;delete shape2;return 0;
}
在这个例子中,定义了一个接口Shape,其中包含纯虚函数draw()。
然后,创建了两个实现了该接口的类Circle和Rectangle,并分别实现了draw()方法。
在main()函数中,创建了两个接口指针shape1和shape2,分别指向Circle和Rectangle的对象。通过这两个指针,可以以统一的方式调用不同的实现类的方法,实现了多态性。
用代码说明“隐藏实现细节”
#include <iostream>// 定义接口(抽象类)
class Database {
public:virtual void connect() = 0; // 纯虚函数virtual void query(const std::string& sql) = 0; // 纯虚函数
};// 实现接口的类
class MySQLDatabase : public Database {
public:void connect() override {std::cout << "Connected to MySQL database." << std::endl;}void query(const std::string& sql) override {std::cout << "Executing query: " << sql << std::endl;// 实际的查询逻辑}
};int main() {// 使用接口指针调用接口的方法,隐藏了具体实现的细节Database* db = new MySQLDatabase();db->connect();db->query("SELECT * FROM customers");delete db;return 0;
}
在这个例子中,定义了一个接口Database,其中包含纯虚函数connect()和query()。
然后,创建了一个实现了该接口的类MySQLDatabase,并实现了这两个方法。
在main()函数中,通过接口指针db调用接口的方法,而不需要关心具体实现的细节。这样,可以隐藏实现的细节,只需要使用接口提供的方法即可。
为了更好的说明“通过接口隐藏实现细节”,现在我来假设一个场景:
我是一个主程序员,然后还下辖了另一个程序员。
现在我发现程序需要对数据库进行操作,然后我就用抽象类了定义一个数据库操作类,在这个数据库操作类里面用虚函数写了很多我认为程序会使用到的函数。
之后,我把实现这个抽象类——数据库操作类的任务交给了我下辖的程序员。
我下辖的程序员实现后,我只需要通过这个抽象类或者说接口通过指针或引用直接调用我下辖的程序员实现的功能就可以了,我不需要知道他是怎么实现的。
用代码说明“实现代码解耦“
#include <iostream>// 定义接口(抽象类)
class Logger {
public:virtual void log(const std::string& message) = 0; // 纯虚函数
};// 实现接口的类
class ConsoleLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "Console Logger: " << message << std::endl;}
};class FileLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "File Logger: " << message << std::endl;// 将日志写入文件}
};class LogManager {
private:Logger* logger;public:LogManager(Logger* logger) {this->logger = logger;}void doLog(const std::string& message) {logger->log(message);}
};int main()
{// 创建不同的日志记录器对象,并将其注入到日志管理器中Logger* consoleLogger = new ConsoleLogger();Logger* fileLogger = new FileLogger();LogManager logManager1(consoleLogger);LogManager logManager2(fileLogger);// 调用日志管理器的方法,实现了代码的解耦 logManager1.doLog("This is a log message from console logger."); logManager2.doLog("This is a log message from file logger.");delete consoleLogger; delete fileLogger;return 0;
}
在这个例子中,定义了一个接口Logger,其中包含纯虚函数log()。
然后,创建了两个实现了该接口的类ConsoleLogger和FileLogger,并分别实现了log()方法。
接下来,创建了一个LogManager类,其中包含一个Logger指针成员变量。在LogManager的构造函数中,将不同的日志记录器对象注入到LogManager中。
在main()函数中,创建了两个LogManager对象logManager1和logManager2,分别使用了ConsoleLogger和FileLogger作为日志记录器。通过调用LogManager的方法,实现了代码的解耦,不同的日志记录器对象可以被注入到LogManager中,实现了灵活的日志记录功能。
相关文章:
C++中的接口有什么用
2023年12月13日,周三上午 今天上午在适配器模式,我发现如果想真正理解适配器模式,就必须学会使用C中的接口,就必须明白为什么要在C中使用接口,所以重新学习了一下C中的接口 目录 C中的接口有什么用用代码说明“实现多…...
el-table合并相同数据的单元格
相同的数据合并单元格 <el-table :data"userList" :span-method"objectSpanMethod" border><el-table-column type"selection" width"50" align"center" /><el-table-column label"用户名称" a…...
Verilog Systemverilog define宏定义
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 文章前情预告一、define是个啥?二、为什么要使用define三、怎么使用define四、define的横向拓展五、define思想在生活中的体现!六、结论七、参考资料八、…...
51单片机应用从零开始(十一)·数组函数、指针函数
51单片机应用从零开始(九)数组-CSDN博客 51单片机应用从零开始(十)指针-CSDN博客 目录 1. 用数组作函数参数控制流水花样 2. 用指针作函数参数控制 P0 口 8 位 LED 流水点亮 1. 用数组作函数参数控制流水花样 要在51单片机中…...
【PostgreSQL】从零开始:(八)PostgreSQL-数据库PSQL元命令
元命令 postgres# \? General\bind [PARAM]... set query parameters\copyright show PostgreSQL usage and distribution terms\crosstabview [COLUMNS] execute query and display result in crosstab\errverbose show most recent error…...
02 使用Vite创建Vue3项目
概述 A Vue project is structured similarly to a lot of modern node-based apps and contains the following: A package.json fileA node_modules folder in the root of your projectVarious other configuration files are usually contained at the root level, such …...
Shell三剑客:sed(简介)
一、前言 Stream EDitor:流编辑 sed 是一种在线的、非交互式的编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后&…...
tp连接数据库
ThinkPHP内置了抽象数据库访问层,把不同的数据库操作封装起来,我们只需要使用公共的Db类进行操作,而无需针对不同的数据库写不同的代码和底层实现,Db类会自动调用相应的数据库驱动来处理。采用PDO方式,目前包含了Mysql…...
jmeter,断言:响应断言、Json断言
一、响应断言 接口A请求正常返回值如下: {"status": 10013, "message": "user sign timeout"} 在该接口下创建【响应断言】元件,配置如下: 若断言成功,则查看结果树的接口显示绿色,若…...
dockerfite创建镜像---INMP+wordpress
搭建dockerfile---lnmp 在192.168.10.201 使用 Docker 构建 LNMP 环境并运行 Wordpress 网站平台 [rootdocker1 opt]# mkdir nginx mysql php [rootdocker1 opt]# ls #分别拖入四个包: nginx-1.22.0.tar.gz mysql-boost-5.7.20.tar.gz php-7.1.10.tar.bz2 wor…...
服务器数据恢复—raid5热备盘未激活崩溃导致上层oracle数据丢失的数据恢复案例
服务器数据恢复环境: 某品牌X系列服务器,4块SAS硬盘组建了一组RAID5阵列,还有1块磁盘作为热备盘使用。服务器上层安装的linux操作系统,操作系统上部署了一个基于oracle数据库的OA(oracle已经不再为该OA系统提供后续服务…...
生产派工自动化:MES系统的关键作用
随着制造业的数字化转型和智能化发展,生产派工自动化成为了提高生产效率、降低成本,并实现优质产品生产的关键要素之一。制造执行系统(MES)在派工自动化中发挥着重要作用,通过实时数据采集和智能调度,优化生…...
netty-daxin-2(netty常用事件讲解)
文章目录 netty常用事件讲解ChannelHandler接口ChannelHandler适配器类ChannelInboundHandler 子接口Channel 的状态调用时机ChannelHandler 生命周期示例NettServer&CustomizeInboundHandlerNettyClient测试分析 ChannelInboundHandlerAdapter适配器类SimpleChannelInboun…...
使用playbook部署k8s集群
1.部署ansible集群 使用python脚本一个简单的搭建ansible集群-CSDN博客 2.ansible命令搭建k8s: 1.主机规划: 节点IP地址操作系统配置server192.168.174.150centos7.92G2核client1192.168.174.151centos7.92G2核client2192.168.174.152centos7.92G2 …...
Python基础入门第四节,第五节课笔记
第四节 第一个条件语句 if 条件: 条件成立执行的代码1 条件成立执行的代码2 ...... else: 条件不成立执行的代码1 条件不成立执行的代码2 …… 代码如下: 身高 float(input("请输入您的身高(米):")) if 身高 >1.3:print(f您的身高是{身高},已经超过1.3米,您需…...
基于Java SSM框架实现智能停车场系统项目【项目源码+论文说明】
基于java的SSM框架实现智能停车场系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述…...
React系列:useEffect的使用
useEffect的使用 useEffect的第二个参数不同,useEffect的加载不同 当第二个参数为没有的时候 只在组件初始渲染和组件更新之后加载当第二个参数为[] 的时候 只在初始渲染之后加载当第二个参数为[有依赖] 的时候 只在初始渲染之后和依赖修改的时候进行加载 functi…...
Ps:形状工具 - 描边选项
在形状工具的工具选项栏或“属性”面板中,单击“设置形状描边类型” Set shape stroke type菜单图标可打开“描边选项” Stroke Options面板。 描边预设 Stroke Type 默认列出了实线、虚线和点线三种类型的描边,单击可应用。 自己创建并存储的描边类型&a…...
C#基础知识 - 变量、常量与数据类型篇
C#基础知识 - 变量、常量与数据类型篇 第3节 变量、常量与数据类型3.1 C#变量3.1.1 变量使用3.1.2 自定义变量3.1.2 接收用户输入 3.2 C#常量3.2.1 常量的使用 3.3 C#数据类型3.3.1 数据类型之值类型3.3.2 数据类型之引用类型 更多C#基础知识详解请查看:C#基础知识 …...
Java面向对象思想以及原理以及内存图解
文章目录 什么是面向对象面向对象和面向过程区别创建一个对象用什么运算符?面向对象实现伪代码面向对象三大特征类和对象的关系。 基础案例代码实现实例化创建car对象时car引用的内存图对象调用方法过程 成员变量和局部变量作用范围在内存中的位置 关于对象的引用关系简介相关…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
