C++ 设计模式 Forward Declaration Pimpl
放几轮跟 chatgpt 的对话,很精彩的回答
You
我有个问题,我的 main 目标依赖 src/gcp_subscriber.h 的 GCPSubscriber class
这个 class 有个 private 成员 google::cloud::pubsub::Subscriber
也就意味着我得在 gcp_subscriber.h 里面引用 google cloud 的依赖库。
也就意味着 main 也会 include 到 google cloud 依赖库,这会减慢我的 main 目标编译速度
ChatGPT
在 C++ 中,使用前置声明(forward declaration)可以避免引入完整的头文件而只引入所需的类的声明。通过使用前置声明,你可以减少编译时需要处理的代码量,从而提高编译速度。
在你的 gcp_subscriber.h 中,尝试使用前置声明而不是包含整个 google/cloud/pubsub/subscriber.h 头文件。只在实现文件中(例如 gcp_subscriber.cpp)引入完整的头文件。这样可以将依赖库的具体实现细节延迟到编译阶段的实现文件中,从而加速主目标的编译。
以下是一个示例:
gcp_subscriber.h:
#ifndef GCP_SUBSCRIBER_H_
#define GCP_SUBSCRIBER_H_#include <memory> // 如果使用了 std::shared_ptr// Forward declaration of google::cloud::pubsub::Subscriber
namespace google::cloud::pubsub {
class Subscriber;
} // namespace google::cloud::pubsubclass GCPSubscriber {
public:GCPSubscriber(std::string channel, std::shared_ptr<MessageBufferQueue> queue);void block_receive();private:std::shared_ptr<MessageBufferQueue> queue;std::unique_ptr<google::cloud::pubsub::Subscriber> subscriber;
};#endif // GCP_SUBSCRIBER_H_
gcp_subscriber.cpp:
#include "gcp_subscriber.h"
#include <google/cloud/pubsub/subscriber.h>GCPSubscriber::GCPSubscriber(std::string channel, std::shared_ptr<MessageBufferQueue> queue): queue(queue),subscriber(std::make_unique<google::cloud::pubsub::Subscriber>(google::cloud::pubsub::MakeSubscriberConnection(google::cloud::pubsub::Subscription("combo-001", fmt::format("cme-mktdata-{}-NR", channel)))))
{
}void GCPSubscriber::block_receive() {// 实现 block_receive 函数的具体内容// ...
}
通过这种方式,gcp_subscriber.h 只需要知道 google::cloud::pubsub::Subscriber 的存在,而不需要知道它的具体实现细节。这有助于减少 main 目标的编译时间,因为它不再需要处理完整的 google/cloud/pubsub/subscriber.h。
省略中间一些对话
You
那这前置声明不就失效了吗
ChatGPT
你是对的,我为之前的回答道歉。由于需要在 gcp_subscriber.h 中的实现文件 (gcp_subscriber.cc) 中使用完整的 google::cloud::pubsub::Subscriber,前置声明就不再适用了。
在这种情况下,你需要在 gcp_subscriber.h 中包含完整的头文件,以便确保 google::cloud::pubsub::Subscriber 的定义是可见的。这将导致包含 Google Cloud Pub/Sub 相关的头文件,从而增加了编译时间。解决方案是确保只在需要的地方包含这些头文件,以尽量减小编译时间的影响。
如果你的项目结构允许,可以考虑将 google::cloud::pubsub::Subscriber 的具体实现移到实现文件(如 gcp_subscriber.cc)中,而不是将其定义放在头文件中。这样,头文件只需要进行前置声明,而不必包含完整的定义。这样可以减小头文件的依赖,提高编译速度。例如:
gcp_subscriber.h:
#ifndef GCP_SUBSCRIBER_H_
#define GCP_SUBSCRIBER_H_#include <memory>class MessageBufferQueue; // 前置声明class GCPSubscriber {
public:GCPSubscriber(std::string channel, std::shared_ptr<MessageBufferQueue> queue);void block_receive();private:std::shared_ptr<MessageBufferQueue> queue;class Impl; // 前置声明std::unique_ptr<Impl> subscriber_impl;
};#endif // GCP_SUBSCRIBER_H_
gcp_subscriber.cc:
#include "gcp_subscriber.h"
#include <google/cloud/pubsub/subscriber.h>class GCPSubscriber::Impl {
public:google::cloud::pubsub::Subscriber subscriber;// ... 其他成员和实现
};GCPSubscriber::GCPSubscriber(std::string channel, std::shared_ptr<MessageBufferQueue> queue): queue(queue), subscriber_impl(std::make_unique<Impl>())
{// 对 Impl 进行初始化,包括创建 google::cloud::pubsub::Subscriber
}void GCPSubscriber::block_receive() {// 实现 block_receive 函数的具体内容,使用 subscriber_impl->subscriber// ...
}
这种方式可以将 Google Cloud Pub/Sub 的具体实现从头文件中移除,从而减小编译时的依赖。
You
这是 pimpl 吗
ChatGPT
是的,这种技术被称为 Pimpl(Pointer to Implementation)或者又称为 Opaque Pointer。Pimpl 是一种设计模式,其主要目标是将类的实现细节(成员变量、成员函数的实现等)隐藏在一个独立的类中,以减小头文件的依赖,提高封装性,同时降低编译时的依赖性。
在 Pimpl 模式中,类的头文件只包含对实现类的前置声明,而实现类的定义则放在实现文件中。这样,只有在实现文件中才需要包含具体的头文件,而头文件中则只需要包含前置声明,从而减小了编译时的依赖。
这对于减小编译时间和隐藏实现细节非常有用。同时,当实现发生变化时,只需要修改实现文件,而头文件可以保持不变,从而减小了对外部代码的影响。
在你的例子中,GCPSubscriber 类的具体实现被封装在 GCPSubscriber::Impl 类中,而 GCPSubscriber 的头文件中只包含了 MessageBufferQueue 的前置声明和 Impl 的前置声明,从而隐藏了 google::cloud::pubsub::Subscriber 的具体实现。
相关文章:
C++ 设计模式 Forward Declaration Pimpl
放几轮跟 chatgpt 的对话,很精彩的回答 You 我有个问题,我的 main 目标依赖 src/gcp_subscriber.h 的 GCPSubscriber class 这个 class 有个 private 成员 google::cloud::pubsub::Subscriber 也就意味着我得在 gcp_subscriber.h 里面引用 google clou…...
【uniapp】小程序开发8:滚动组件scroll-view
我们经常需要做页面中部分内容可以滚动的功能,例如“猜你喜欢”,内容太多,通常都会超出屏幕,那么此块区域应该可以滚动,但是顶部的自定义导航栏应该不能随着滚动。 这个时候,就可以使用uniapp提供的滚动组件…...
Java王者荣耀火柴人
主要功能 键盘W,A,S,D键:控制玩家上下左右移动。按钮一:控制英雄发射一个矩形攻击红方小兵。按钮控制英雄发射魅惑技能,伤害小兵并让小兵停止移动。技能三:攻击多个敌人并让小兵停止移动。普攻:对小兵造成基础伤害。小…...
1.鸿蒙应用程序开发app_hap开发环境搭建
1.下载Node.js, Javascipts的运行环境 node.js版本下载v12.18.3/https://www.cnblogs.com/txwtech/p/17865780.html 2.下载并安装DevEco Studio DevEco Studio 3.1 DevEco Studio 3.1配套支持HarmonyOS 3.1版本及以上的应用及服务开发,提供了代码智能编辑、低代…...
JDK多版本集成 Jacoco 配置指南
JDK多版本集成 Jacoco 配置指南 本篇相关 JDK 版本配置如下: JDK8 JDK11 JDK17 Jacoco 是什么 Jacoco 是一个用于Java程序的代码覆盖率报告工具。它通过动态分析(在代码执行时收集数据)来生成代码覆盖率报告文件。Jacoco 支持多种覆盖率标…...
容器及容器调度(云)
在云计算中,容器是一种轻量级、可执行的软件包,它包含应用程序及其全部依赖项,包括库、二进制文件、配置文件等。容器与虚拟机不同,因为它们不需要包含完整的操作系统;相反,所有容器都共享主机操作系统的内…...
实验七 子网的划分
实验七 子网的划分 实验目的掌握划分子网的方法实验内容划分给定IP地址的子网将划分后的子网应用到网络环境中实验要求每位同学从下表中至少选择一行进行子网划分,并填写所选择行的剩余部分。(注意:子网号全0的不用)标准IP地址 要求划 分子网数 借用的主机位数 子网掩码 第…...
Proteus仿真--射击小游戏仿真设计
本文介绍基于proteus射击小游戏仿真设计(完整仿真源文件及代码见文末链接) 仿真图如下 K1-K4为4个按键,用于上移、下移、确认等,模拟单机游戏 仿真运行视频 Proteus仿真--射击小游戏仿真设计 附完整Proteus仿真资料代码资料 …...
docker的资源控制:
docker的资源控制: 对容器的使用宿主机的资源进行限制 cpu 内存 磁盘i/0 docker使用linux自带的功能cgroup control grouos是linux内核系统提供的一种可以限制,记录,隔离进程所使用的物理资源 control grouos是linux内核系统提供的一种可…...
Leo赠书活动-13期 【以企业架构为中心的SABOE数字化转型五环法】文末送书
Leo赠书活动-13期 【以企业架构为中心的SABOE数字化转型五环法】文末送书 ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客…...
【人工智能 | 知识表示方法】状态空间法 语义网络,良好的知识表示是解题的关键!(笔记总结系列)
🤵♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…...
华清远见嵌入式学习——QT——作业1
作业要求: 代码: ①:头文件 #ifndef LOGIN_H #define LOGIN_H#include <QWidget> #include <QLineEdit> //行编辑器类 #include <QPushButton> //按钮类 #include <QLabel> //标签类 #include <QM…...
MYSQL练习创建存储函数和存储过程
创建数据表,信息如下: 表结构: 字段名 数据类型 主键 外键 非空 唯一 自增 id INT 是 否 是 是 否 name VARCHAR(50) 否 否 是 否 否 glass VARCHAR(50) 否 否 是 否…...
Java基础语法面试题
数据类型 Java有哪些数据类型 定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类 型,在内存中分配了不同大小的内存空间。 分类: 基本数据类型 数值型 整数类型(byte,short,int,long) 浮点类型(float,dou…...
结合ColorUI组件开发微信小程序
1.自定义组件生命周期函数: Component({data: {},attached() {console.log("自定义组件生命周期函数 attached--先执行");this.getPos();},ready() {console.log("ready生命周期函数---在attached之后执行")},methods: {getPos() {var that th…...
如何搭建废品上门回收小程序
如今,随着环境保护意识的增强,废品的回收和再利用变得越来越重要。为了方便人们进行废品回收,搭建一个废品上门回收的小程序成为了一个不错的选择。本文将介绍如何从零开始搭建一个废品上门回收小程序。 …...
蓝牙配对、连接和删除汇总
目的:处理PC连接蓝牙设备的配对、连接和删除操作,以及常见故障。 命令行配对蓝牙设备并连接 要求:配对BLUET043蓝牙,密码为4444,然后连接该蓝牙。操作步骤如下: Step1.下载 修复工具,然后安装…...
Linux网络——高级IO
目录 一.五种IO模型 1.阻塞式IO 2.非阻塞式IO 3.信号驱动IO 4.多路转接IO: 5.异步IO 二.同步通信 vs 异步通信 三.设置非阻塞IO 1.阻塞 vs 非阻塞 2.非阻塞IO 3.实现函数SetNoBlock 四.I/O多路转接之select 1.初识select 2.select函数原型 3.socket就绪…...
Java注解详解
概述 注解是对程序代码进行标注和解释的一种方式。在Java中,注解提供了一种元数据形式,能够在程序中嵌入有关程序的信息,以便进行进一步的处理。注解通过使用符号来声明,如Override、Deprecated等。 注解和注释的区别 注释&…...
Android wifi 框架以及Enable流程
Android P相比于Android O的变化 多了WifiStateMachinePrime(状态机的前处理机制),wifiService的相关cmd 不再是直接send 给WifiStateMachine,而是被送到WifiStateMachinePrime先进行处理后,再送往WifiStateMachine也…...
别再把AI当聊天机器人了:Claude Code之父的“15倍速”工程化工作流全拆解
在这个AI编程工具层出不穷的时代,大多数人还在纠结“哪家大模型的代码补全更准”,或者在对话框里一行行地复制粘贴代码。然而,Anthropic工程师、Claude Code的缔造者Boris Cherny最近在X上公开的一套工作流,直接震碎了开发者社区的…...
探索iPad Pro的深度数据获取
在iOS开发中,获取深度数据是一个非常有趣的话题,特别是在使用双摄像头设备时。然而,当我们尝试将这些技术应用到iPad Pro上时,可能会遇到一些独特的挑战和限制。下面我们将深入探讨如何在iPad Pro上获取深度数据,以及为什么有些功能在iPad上不可用。 背景介绍 Apple在WW…...
AI 编程盛行的时代,为什么 “『DC- WFW』” 仍然具有必要性?
AI训练存储选型的演进路线 第一阶段:单机直连时代 早期的深度学习数据集较小,模型训练通常在单台服务器或单张GPU卡上完成。此时直接将数据存储在训练机器的本地NVMe SSD/HDD上。 其优势在于IO延迟最低,吞吐量极高,也就是“数据离…...
MiniCPM-o-4.5-nvidia-FlagOS插件开发指南:为谷歌浏览器打造智能阅读与摘要助手
MiniCPM-o-4.5-nvidia-FlagOS插件开发指南:为谷歌浏览器打造智能阅读与摘要助手 你是不是经常在网上冲浪时,面对一篇长文感到头疼,只想快速抓住核心要点?或者遇到一篇外文资料,需要逐句翻译才能理解?又或者…...
Notepad-- 终极中文编辑器:从零开始打造你的专属高效文本工作流
Notepad-- 终极中文编辑器:从零开始打造你的专属高效文本工作流 【免费下载链接】notepad-- 一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。 项目地址: https://gitcode.com/GitHub_Trending/no/notepad-- …...
收藏必备!小白程序员轻松入门大模型,带你理清AI核心概念全框架
AI浪潮已经刮了一年多,身边越来越多人聊AI,张口就是“agent”“skill”,听得人只能点头附和,似懂非懂?其实不是听不懂,而是没有把这些概念串起来,告诉你它们到底是什么、彼此有啥关系。 咱不聊复…...
小白程序员必看:收藏这份LangChain Agent开发指南,轻松入门大模型时代!
本文以LangChain框架为核心,详细介绍了如何开发AI Agent。内容涵盖模型调用、工具封装、会话记忆保存等基础功能,通过实操案例帮助读者理解Agent开发流程。LangChain简化了模型集成和工具调用,并提供了记忆模块支持多轮对话。文章适合想要入门…...
工业机器人离线编程与仿真——RobotStudio基础学习3.27
工业机器人离线编程与仿真——RobotStudio基础学习 一、工业机器人离线编程认知 1.1 工业机器人常用编程方法 工业机器人主流编程方法分为示教编程和离线编程两类,二者核心差异体现在编程环境、对生产的影响等方面,具体对比见下表: 示教编…...
3步解锁知识自由:ScienceDecrypting永久破解文档限制
3步解锁知识自由:ScienceDecrypting永久破解文档限制 【免费下载链接】ScienceDecrypting 破解CAJViewer带有效期的文档,支持破解科学文库、标准全文数据库下载的文档。无损破解,保留文字和目录,解除有效期限制。 项目地址: htt…...
彻底解决Windows磁盘空间危机:Driver Store Explorer专业驱动管理指南
彻底解决Windows磁盘空间危机:Driver Store Explorer专业驱动管理指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 你是否曾为Windows系统盘空间不断缩小而烦恼ÿ…...
