当前位置: 首页 > news >正文

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日&#xff0c;周三上午 今天上午在适配器模式&#xff0c;我发现如果想真正理解适配器模式&#xff0c;就必须学会使用C中的接口&#xff0c;就必须明白为什么要在C中使用接口&#xff0c;所以重新学习了一下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宏定义

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 文章前情预告一、define是个啥&#xff1f;二、为什么要使用define三、怎么使用define四、define的横向拓展五、define思想在生活中的体现!六、结论七、参考资料八、…...

51单片机应用从零开始(十一)·数组函数、指针函数

51单片机应用从零开始&#xff08;九&#xff09;数组-CSDN博客 51单片机应用从零开始&#xff08;十&#xff09;指针-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 是一种在线的、非交互式的编辑器&#xff0c;它一次处理一行内容。处理时&#xff0c;把当前处理的行存储在临时缓冲区中&#xff0c;称为“模式空间”(pattern space)&#xff0c;接着用sed命令处理缓冲区中的内容&#xff0c;处理完成后&…...

tp连接数据库

ThinkPHP内置了抽象数据库访问层&#xff0c;把不同的数据库操作封装起来&#xff0c;我们只需要使用公共的Db类进行操作&#xff0c;而无需针对不同的数据库写不同的代码和底层实现&#xff0c;Db类会自动调用相应的数据库驱动来处理。采用PDO方式&#xff0c;目前包含了Mysql…...

jmeter,断言:响应断言、Json断言

一、响应断言 接口A请求正常返回值如下&#xff1a; {"status": 10013, "message": "user sign timeout"} 在该接口下创建【响应断言】元件&#xff0c;配置如下&#xff1a; 若断言成功&#xff0c;则查看结果树的接口显示绿色&#xff0c;若…...

dockerfite创建镜像---INMP+wordpress

搭建dockerfile---lnmp 在192.168.10.201 使用 Docker 构建 LNMP 环境并运行 Wordpress 网站平台 [rootdocker1 opt]# mkdir nginx mysql php [rootdocker1 opt]# ls #分别拖入四个包&#xff1a; nginx-1.22.0.tar.gz mysql-boost-5.7.20.tar.gz php-7.1.10.tar.bz2 wor…...

服务器数据恢复—raid5热备盘未激活崩溃导致上层oracle数据丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌X系列服务器&#xff0c;4块SAS硬盘组建了一组RAID5阵列&#xff0c;还有1块磁盘作为热备盘使用。服务器上层安装的linux操作系统&#xff0c;操作系统上部署了一个基于oracle数据库的OA&#xff08;oracle已经不再为该OA系统提供后续服务…...

生产派工自动化:MES系统的关键作用

随着制造业的数字化转型和智能化发展&#xff0c;生产派工自动化成为了提高生产效率、降低成本&#xff0c;并实现优质产品生产的关键要素之一。制造执行系统&#xff08;MES&#xff09;在派工自动化中发挥着重要作用&#xff0c;通过实时数据采集和智能调度&#xff0c;优化生…...

netty-daxin-2(netty常用事件讲解)

文章目录 netty常用事件讲解ChannelHandler接口ChannelHandler适配器类ChannelInboundHandler 子接口Channel 的状态调用时机ChannelHandler 生命周期示例NettServer&CustomizeInboundHandlerNettyClient测试分析 ChannelInboundHandlerAdapter适配器类SimpleChannelInboun…...

使用playbook部署k8s集群

1.部署ansible集群 使用python脚本一个简单的搭建ansible集群-CSDN博客 2.ansible命令搭建k8s&#xff1a; 1.主机规划&#xff1a; 节点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语言开发一个智能停车场管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述…...

React系列:useEffect的使用

useEffect的使用 useEffect的第二个参数不同&#xff0c;useEffect的加载不同 当第二个参数为没有的时候 只在组件初始渲染和组件更新之后加载当第二个参数为[] 的时候 只在初始渲染之后加载当第二个参数为[有依赖] 的时候 只在初始渲染之后和依赖修改的时候进行加载 functi…...

Ps:形状工具 - 描边选项

在形状工具的工具选项栏或“属性”面板中&#xff0c;单击“设置形状描边类型” Set shape stroke type菜单图标可打开“描边选项” Stroke Options面板。 描边预设 Stroke Type 默认列出了实线、虚线和点线三种类型的描边&#xff0c;单击可应用。 自己创建并存储的描边类型&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#基础知识详解请查看&#xff1a;C#基础知识 …...

Java面向对象思想以及原理以及内存图解

文章目录 什么是面向对象面向对象和面向过程区别创建一个对象用什么运算符?面向对象实现伪代码面向对象三大特征类和对象的关系。 基础案例代码实现实例化创建car对象时car引用的内存图对象调用方法过程 成员变量和局部变量作用范围在内存中的位置 关于对象的引用关系简介相关…...

物联网技术如何重塑智能电网的底层架构

1. 物联网技术重塑智能电网的底层逻辑2003年美加大停电事故导致5000万人陷入黑暗&#xff0c;这场灾难直接催生了现代智能电网的诞生。如今&#xff0c;当我们谈论智能电网时&#xff0c;本质上是在讨论一个由物联网(IoT)技术重构的能源神经系统。这个系统通过海量智能终端实时…...

ElevenLabs声音库资源推荐,从免费层到企业级Tier 4权限全解锁:含3个已下架但仍在灰度测试的传奇音色

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;ElevenLabs声音库资源推荐 ElevenLabs 提供了业界领先的高质量语音合成服务&#xff0c;其声音库涵盖多语种、多风格及可定制化角色音色。官方声音库分为三类&#xff1a;预置语音&#xff08;Prebuilt…...

基于Agentify框架构建AI智能体:从核心原理到实战应用

1. 项目概述&#xff1a;从代码仓库到智能体构建平台最近在开源社区里&#xff0c;一个名为harindukavishka/agentify的项目引起了我的注意。乍一看&#xff0c;这只是一个GitHub上的代码仓库&#xff0c;但当你点进去&#xff0c;深入其文档和代码结构&#xff0c;你会发现它远…...

RAG 失效的真正原因,长上下文救不了 RAG

最早大家做 RAG&#xff0c;是因为模型上下文太短&#xff0c;一次塞不进完整文档&#xff0c;只能先检索&#xff0c;再把相关片段交给模型回答。后来&#xff0c;模型上下文窗口越来越长&#xff0c;从 32K、128K 到百万 token&#xff0c;很多人开始觉得&#xff1a;RAG 可能…...

机器人抓取仿真与数据分析:从PyBullet集成到抓取性能评估

1. 项目概述与核心价值最近在机器人控制与仿真领域&#xff0c;一个名为PyroMind-Dynamics/openclaw-tracer的项目引起了我的注意。乍一看这个标题&#xff0c;它像是一个典型的GitHub仓库名&#xff0c;由组织名“PyroMind-Dynamics”和项目名“openclaw-tracer”组成。作为一…...

构建工程化提示词库:提升AI开发效率与代码质量

1. 项目概述&#xff1a;一个面向开发者的提示词库如果你和我一样&#xff0c;在过去的几年里深度参与了AI应用开发&#xff0c;尤其是基于大语言模型&#xff08;LLM&#xff09;的各类项目&#xff0c;那你一定对“提示工程”这个词又爱又恨。爱的是&#xff0c;一段精心设计…...

WechatSogou微信公众号爬虫实战指南:高效获取公众号数据的Python解决方案

WechatSogou微信公众号爬虫实战指南&#xff1a;高效获取公众号数据的Python解决方案 【免费下载链接】WechatSogou 基于搜狗微信搜索的微信公众号爬虫接口 项目地址: https://gitcode.com/gh_mirrors/we/WechatSogou 在信息爆炸的时代&#xff0c;微信公众号已成为内容…...

全国青少年信息素养大赛初赛(算法创意实践挑战赛C++初中组:样题带解析)

一、选择题 1、现有数组定义为 int array[5] {1};&#xff0c;数组 array 中的 元素分别是_____ A. 1 2 3 4 5 B. 0 0 0 0 1 C. 0 0 0 0 0 D. 1 0 0 0 0 答案&#xff1a;D 解析&#xff1a;int类型的数组中未赋值的元素&#xff0c;初始化赋值为0 2、在 C语言中&#…...

093、Python自动化测试:pytest框架

093、Python自动化测试:pytest框架 上周排查一个线上问题,凌晨两点盯着日志发现某个数据校验函数漏了边界条件。手动复现、加打印、重启服务,折腾到天亮才定位到是类型转换时的浮点精度问题。同事早上看到我黑眼圈,扔过来一句:“早用pytest写个参数化测试,这种边界问题跑…...

保姆级教程:用Python搞定安居客滑块验证码(附AES加密与轨迹生成源码)

Python实战&#xff1a;破解安居客滑块验证码的完整技术方案 滑块验证码已经成为现代网站反爬机制的重要组成部分。对于开发者而言&#xff0c;理解其工作原理并实现自动化解决方案&#xff0c;不仅能提升爬虫效率&#xff0c;也是技术能力的体现。本文将深入解析安居客滑块验证…...