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也…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
