C++ PImpl模式、指向实现的指针、PImpl Idiom、隐藏实现细节

C++ PImpl模式、指向实现的指针、PImpl Idiom、隐藏实现细节

flyfish

PImpl 全称是 “Pointer to Implementation”,在中文中通常翻译为“指向实现的指针”或者“指向实现”。PImpl 是一种编程技巧,通常用于 C++ 中,通过这种技术,可以隐藏类的实现细节,达到信息隐藏和二进制兼容性的目的。PImpl 也被称为“编译防火墙”(Compilation Firewall)。

PImpl 模式在遇到以下情况下可以使用:

如果是在简单场景下,不使用 PImpl 的实现更直接,如果遇到下面的情况,就可以使用PImpl 的方式。

1 隐藏实现细节:

如果你想要隐藏类的内部实现细节,使得用户只需要知道类的接口,而无需了解具体实现。
这在发布库或 API 时特别有用,可以避免用户代码依赖于类的具体实现,从而提高封装性。

2 减少编译依赖:

如果你的类实现可能经常改变,而不希望每次改变都导致所有依赖该类的代码重新编译。
例如,当一个类的成员变量或内部实现发生变化时,使用 PImpl 模式可以避免重新编译所有包括这个头文件的文件。

3提高二进制兼容性:

在需要保持 ABI(应用程序二进制接口)稳定的场景下,PImpl 模式可以在不改变类接口的前提下,修改类的实现细节,从而提高二进制兼容性。 如果你需要确保类的接口稳定,并希望在不改变接口的情况下能够自由地修改实现细节,PImpl 是一个合适的选择。

4 管理复杂实现:

当类的实现变得非常复杂时,将实现细节放在单独的实现类中,有助于保持代码的清晰和可维护性。

其他名字

Cheshire Cat:这个名字来源于《爱丽丝梦游仙境》中的柴郡猫,它有时会隐形,只留下笑脸。这个比喻形象地描述了 PImpl 模式隐藏实现细节的特性。
Compiler Firewall:这个名字强调了 PImpl 模式可以减少编译依赖,像防火墙一样隔离实现和接口。
d-pointer:这个名字主要在 Qt 库中使用,指的是 “指向数据(implementation)的指针”。

+---------------------+       +---------------------+
|      MyClass        |       |    MyClass::Impl    |
|---------------------|       |---------------------|
| - pImpl: Impl*      |       | - someData: int     |
|---------------------|       |---------------------|
| + MyClass()         |       | + Impl()            |
| + ~MyClass()        |       | + ~Impl()           |
| + someMethod()      |       | + someMethodImpl()  |
+---------------------+       +---------------------+|                                 |+-------------------+-------------+|has a ||+--------v---------+|    std::unique_ptr||-------------------||     - Impl        |+-------------------+

C++ 里的 “has a”

在 C++ 编程中,“has a” 关系指的是成员对象或成员指针的关系。也就是说,一个类拥有另一个类的对象或指针作为其成员。这种关系与继承(“is a”)不同:
“has a”(组合关系):一个类包含另一个类的对象或指针。
“is a”(继承关系):一个类继承自另一个类。
PImpl 模式中,“has a” 关系意味着 MyClass 包含一个 Impl 对象的指针,这个关系表示 MyClass 持有并管理 Impl 对象的生命周期。

示例代码

头文件:MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H#include <memory> // 使用智能指针需要包含这个头文件class MyClass {
public:MyClass(); // 构造函数~MyClass(); // 析构函数void someMethod(); // 公有方法private:// 前向声明一个名为 Impl 的类,这是实现细节类class Impl;// 使用 std::unique_ptr 管理 Impl 的指针std::unique_ptr<Impl> pImpl;
};#endif // MYCLASS_H
源文件:MyClass.cpp
#include "MyClass.h" // 包含头文件// 定义实现类 Impl
class MyClass::Impl {
public:// 实现方法void someMethodImpl() {// 具体的实现细节// 例如,这里我们简单地输出一段文字std::cout << "This is the implementation of someMethod." << std::endl;}
};// 构造函数
MyClass::MyClass() : pImpl(std::make_unique<Impl>()) {// 初始化 pImpl,指向一个新的 Impl 对象
}// 析构函数
MyClass::~MyClass() = default; // 使用默认析构函数,这里会自动释放 pImpl 指向的内存// 公有方法,调用 Impl 类的实现方法
void MyClass::someMethod() {pImpl->someMethodImpl(); // 通过 pImpl 调用具体实现
}
主程序文件:main.cpp
#include "MyClass.h" // 包含 MyClass 类的头文件
#include <iostream> // 用于输出int main() {MyClass myClass; // 创建 MyClass 对象myClass.someMethod(); // 调用公有方法return 0; // 程序结束
}

程序输出:

This is the implementation of someMethod.

说明

  1. 头文件 (MyClass.h)
    class MyClass 定义了一个类,其中有一个私有的指向实现类 Impl 的指针 pImpl
    构造函数和析构函数声明,以及一个公有方法 someMethod 的声明。

  2. 源文件 (MyClass.cpp)
    首先定义 MyClass 的实现类 Impl。这是一个具体实现类,其中包含方法 someMethodImpl
    MyClass::MyClass 构造函数初始化 pImpl,使用 std::make_unique 创建一个新的 Impl 对象。
    MyClass::~MyClass 析构函数默认删除 pImpl,因此不需要手动管理内存。
    MyClass::someMethod 方法调用 pImpl 指向的 Impl 对象的 someMethodImpl 方法。

  3. 主程序文件 (main.cpp)
    创建 MyClass 对象并调用其 someMethod 方法。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

涉案财物管理系统|八大模块可视化展示

涉案财物管理系统DW-S405系统基于物联网技术规范涉案财物管理流程&#xff0c;确保涉案财物的安全性、完整性和合法性&#xff1b;可以提高办案效率&#xff0c;减少办案成本&#xff0c;实现资源共享。 涉案财物管理系统DW-S405主要分为 8 大模块数据展示。 1、案件信息&…

Linux C | 管道open打开方式

Linux C | 管道open打开方式 1.参考 1. 管道 2.现象 是的&#xff0c;这段代码在调用 open(AUDIOIN_FIFO, O_RDONLY) 时可能会被阻塞。原因是 FIFO&#xff08;命名管道&#xff09;在以只读模式打开时&#xff0c;如果没有其他进程以写模式打开该 FIFO&#xff0c;open 调用将…

防火墙综合实验二

目录 实验要求 IP地址配置 需求七 需求八 需求九 需求十 需求十一 实验要求 接防火墙综合实验一&#xff01; 7&#xff0c;办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换)。 8&#xff0c;分公司设备可以通过…

美无定论,娜扎亦菲各自绽放你更爱哪一款?

娜扎亦菲各自绽放你更爱哪一款&#xff1f; 哎呀&#xff0c;这个问题可真是让我头疼呢&#xff0c; 就像让我在两个糖果店里选择最甜的那一颗一样难&#xff01; 古力娜扎和刘亦菲&#xff0c;两位都是娱乐圈里璀璨的明珠&#xff0c; 美得各有千秋&#xff0c;让人怎么舍得…

C++基础入门(上)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 C基础入门(上) 收录于专栏【C语法基础】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. C发展历史 2. C版本…

Goland 通道

channel通道 目录 channel通道 channel介绍 channel基本使用 有缓存通道和无缓存通道的区别 通道的初始化&#xff0c;写入数据到通道&#xff0c;从通道读取数据及基本的注意事项 channel的关闭和遍历 channel的关闭 为什么关闭 如何优雅地关闭通道 channel的遍历 chan…

小众好玩的赛车游戏:环道巨星 CIRCUIT SUPERSTARS中文安装包

《环道巨星》&#xff08;Circuit Superstars&#xff09;是一款由赛车迷亲手为其他赛车迷打造的俯视角赛车游戏。荟集史上各类赛车运动&#xff0c;旨在提供刺激好玩的驾驶体验&#xff1b;而游戏自带的高技术难度将促使玩家长时间磨砺技巧&#xff0c;以达成完美的一圈。 游戏…

【系统架构设计师】九、软件工程(面向对象方法|逆向工程)

目录 六、面向对象方法 6.1 基本概念 6.2 面向对象的分析 6.2.1 用例关系 6.2.2 类之间的关系 6.3 面向对象的设计 6.4 面向对象设计原则与设计模式 6.5 面向对象软件的测试 七、逆向工程 历年真题练习 六、面向对象方法 面向对象的分析方法 (Object-Oriented Analys…

【Linux网络】数据链路层【上】{初识数据链路层/以太网/路由表/MAC地址表/ARP表/NAT表}

文章目录 1.初识数据链路层2.认识以太网2.0前导知识以太网帧和MAC帧CMSA/CD以太网的最小帧长限制是64字节IP层和MAC层 2.1以太网帧格式 3.预备知识计算机网络通信以太网和wifi路由表/MAC地址表/ARP表/NAT表/ACL表 用于同一种数据链路节点的两个设备之间进行信息传递。 1.初识数…

Apache AGE 聚合函数

简介 一般来说&#xff0c;聚合函数 aggr(expr) 会处理每个聚合键在传入记录中找到的所有匹配行&#xff08;键使用等价性进行比较&#xff09;。 在常规聚合&#xff08;即形式为 aggr(expr) 的情况下&#xff09;&#xff0c;聚合值列表是候选值列表&#xff0c;其中所有空…

Clion 使用gdbserver调试FreeSWITCH源码

1.准备环境 window安装clion安装好gdb、ssh、已经编译好的freeswitch可执行文件的docker镜像2.配置clion Settings -> Tools ->SSH Configurations Settings-Build, Execution, Deployment-Toolchains(其实设不设置都行,用默认也行的) Settings-Build, Execution, Depl…

DockerCompose拉取DockerHub镜像,并部署OpenMetaData

参考博主&#xff1a;http://t.csdnimg.cn/i49ET 一、DockerCompose拉取DockerHub镜像 方法一&#xff08;不太行&#xff09;&#xff1a; 在daemon.json文件中添加一些国内还在服务的镜像站&#xff08;可能某些镜像会没有&#xff09; ([ -f /etc/docker/daemon.json ] ||…

人工智能大模型如何助力电商产品经理打造高效的商品工业属性画像

摘要 商品工业属性画像是电商产品经理在进行商品管理、推荐、搜索、广告等业务时的重要依据。通过对商品的工业属性&#xff08;如品类、品牌、规格、功能、风格等&#xff09;的准确识别和标注&#xff0c;可以提高商品的展示效果、匹配度、转化率和用户满意度。然而&#xf…

从概念到完成:Midjourney——设计思维与AI技术的完美结合

文章目录 本文来自 Python学研大本营 作者 学研君 去年 AI 爆火的时候&#xff0c;学研君也赶时髦用上了 Midjourney。平时用它生成图片&#xff0c;感觉生成的图片好看&#xff0c;比上网四处找图更省时省事&#xff0c;更合心意&#xff0c;还不用担心版权问题。 给大家看一下…

102.qt qml-最全Table交互之多列固定、行列拖拽、自定义委托、标题交互使用教程

自定义实现的Table控件&#xff0c;支持跨qt版本&#xff0c;兼容qt5,qt6&#xff01; 截图如下所示: 黑色风格如下所示&#xff1a; 视频演示入口&#xff1a;Qt QML QianWindowV2.5(新增曲线综合示例、QML最全Table交互示例、支持qt5/qt6)_哔哩哔哩_bilibili 1.示例页面入口…

【单片机毕业设计选题24061】-基于蓝牙的单片机通信系统

系统功能: 1、本系统硬件由两块STM32单片机&#xff0c;DHT11&#xff0c;光敏传感器&#xff0c;12864oled和HC-05蓝牙模块组成。 2、单片机1HC-05蓝牙模块做为主机&#xff0c;单片机2HC-05蓝牙模块做为从机。 3、单片机从机将采集到温湿度&#xff0c;光照强度等信息通过…

使用mybatis的statementHander拦截器监控表和字段并发送钉钉消息

新建mybatis的statementHander拦截器拦截器 类 面试题&#xff1a; 2.实现 解析Sql时引入JSqlParser JSqlParser 是一个 SQL 语句解析器。 它将 SQL转换为可遍历的 Java 类层次结构。 <dependency><groupId>com.github.jsqlparser</groupId><artifac…

[IDEA插件] JarEditor 编辑jar包(直接新增、修改、删除jar包内的class文件)

文章目录 1. 安装插件 JarEditor2. 在IDEA中添加外部JAR包3. JarEditor 使用介绍 之前我们需要修改jar内文件的时候需要解压jar包&#xff0c;反编译class&#xff0c;新建java源文件&#xff0c;修改代码&#xff0c;再编译成class&#xff0c;替换jar包内的class文件。 现在…

数据库作业5---视图

创建表 创建部门表&#xff08;dept&#xff09;和员工表&#xff08;emp&#xff09; create table dept(dept_id int primary key auto_increment comment 部门编号,dept_name char(20) comment 部门名称);insert into dept(dept_name) values(销售部),(财务部),(生产部),(…

Day03-索引模板,DSL语句,集群迁移API,ES集群状态统计API,KQL语句及分片重路由API实战

Day03-索引模板&#xff0c;DSL语句&#xff0c;集群迁移API&#xff0c;ES集群状态统计API&#xff0c;KQL语句及分片重路由API实战 1、索引模板1.1 什么是索引模板1.2 查看索引模板1.3 创建/修改索引模板1.4 删除索引模板 2、ES的DSL语句查询2.1 什么是DSL2.2 全文检索-match…