「C/C++」C++设计模式 之 Pimpl模式

news/2024/11/1 18:54:59/

在这里插入图片描述
在这里插入图片描述

✨博客主页
何曾参静谧的博客
📌文章专栏
「C/C++」C/C++程序设计
📚全部专栏
「VS」Visual Studio「C/C++」C/C++程序设计「UG/NX」BlockUI集合
「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发
「QT」QT5程序设计「File」数据文件格式「PK」Parasolid函数说明

目录

    • C++中的Pimpl(Pointer to Implementation)详解
      • 一、引言
      • 二、Pimpl模式的核心思想
      • 三、Pimpl模式的使用步骤
      • 四、Pimpl模式的注意事项
      • 五、Pimpl模式的适用场景
      • 六、总结

C++中的Pimpl(Pointer to Implementation)详解

一、引言

Pimpl(Pointer to Implementation,指向实现的指针)是C++中的一种设计模式,也是一种惯用法,用于实现封装和隐藏类的实现细节。Pimpl模式通过将类的具体实现细节放在一个单独的类中,并在主类中使用指向该实现类的指针,从而实现类的接口与实现的分离。

二、Pimpl模式的核心思想

Pimpl模式的核心思想是将类的实现细节封装在一个独立的类中,并通过一个指针在主类中访问这个实现类。这样做的好处包括:

  1. 减小头文件的依赖性:通过将实现细节放在单独的文件中,可以减少头文件之间的嵌套层级,降低编译依赖,提高编译速度。
  2. 提高封装性:隐藏实现细节,减少对用户的影响,提高代码的模块化程度。
  3. 提高二进制兼容性:当实现细节发生变化时,不需要修改接口,从而保持二进制兼容性。

三、Pimpl模式的使用步骤

  1. 定义公共接口类

    公共接口类只包含类的公共方法和数据成员,这些成员通常是声明为指针的类型,指向实现类。例如:

    // MyClass.h
    #ifndef MYCLASS_H
    #define MYCLASS_H
    #include <memory>class MyClass {
    public:MyClass();~MyClass();void doSomething();private:class MyClassImpl; // 前向声明内部实现类std::unique_ptr<MyClassImpl> impl; // 指向实现类的指针
    };#endif // MYCLASS_H
    
  2. 定义内部实现类

    内部实现类包含实际的数据成员和私有方法,负责类的实际工作。这个类在头文件中进行前向声明,然后在.cpp文件中定义。例如:

    // MyClass.cpp
    #include "MyClass.h"
    #include <iostream>class MyClass::MyClassImpl {
    public:void doSomething() {std::cout << "Doing something." << std::endl;}
    };MyClass::MyClass() : impl(std::make_unique<MyClassImpl>()) {}
    MyClass::~MyClass() {}
    void MyClass::doSomething() {impl->doSomething();
    }
    
  3. 在公共接口类的方法中调用内部实现类的方法

    在公共接口类的方法中,通过指针调用内部实现类的方法,将工作委托给内部实现。例如:

    void MyClass::doSomething() {impl->doSomething();
    }
    

四、Pimpl模式的注意事项

虽然Pimpl模式带来了许多优势,但在使用的过程中也需要注意以下问题:

  1. 构造和析构的成本

    每个实例都需要在堆上分配内存以容纳实现细节,这意味着构造和析构的成本可能会增加。

  2. 内存管理开销

    使用Pimpl会引入额外的内存管理开销,因为需要在堆上分配和释放实现类的内存。

  3. 复制和移动的开销

    复制和移动对象时,必须考虑实现细节的复制或移动开销。通常,使用智能指针(如std::unique_ptr)可以减小这方面的开销。

  4. 不适用于小对象

    如果主类的实现非常小,使用Pimpl可能会引入不必要的开销。

  5. 不适用于不可复制的实现

    如果实现类不支持复制构造函数和赋值运算符,那么主类也将无法被复制。

  6. 动态内存分配的开销

    Pimpl的一个潜在问题是在频繁创建和销毁对象时可能引入的动态内存分配的开销。C++11引入的移动语义对于Pimpl模式尤其有益,通过使用移动构造函数和移动赋值运算符,可以减小Pimpl模式中的拷贝开销,提高性能。

五、Pimpl模式的适用场景

Pimpl模式特别适用于以下场景:

  1. 减小编译依赖

    当一个类的实现细节变动频繁时,使用Pimpl可以减小主类的头文件对其他文件的依赖,加快编译速度。

  2. 隐藏实现细节

    当类的实现细节对用户而言不重要时,使用Pimpl可以隐藏这些细节,提高代码的封装性。

  3. 提高二进制兼容性

    当需要保持二进制兼容性时,使用Pimpl可以在不修改主类接口的情况下修改实现细节。

  4. 实现信息隐藏

    当需要隐藏类的大小和成员信息时,使用Pimpl可以将这些信息移动到实现类中。

六、总结

Pimpl模式是一种强大的C++设计模式,通过隐藏类的实现细节,提供更好的封装和模块化。它有助于减小编译依赖关系,减少编译时间,提高代码的可维护性。然而,在使用Pimpl模式时,也需要注意一些潜在的问题,如构造和析构的成本、内存管理开销等。因此,在性能敏感的情况下,需要谨慎使用Pimpl模式,并进行权衡。


在这里插入图片描述


http://www.ppmy.cn/news/1543663.html

相关文章

Threejs渲染3D字体介绍

概述 本文主要介绍如何通过 Three.js 生成 3D 文本。 效果展示 代码分析 核心代码部分就是通过 Three.js 中的 FontLoader 和 TextGeometry 来加载字体并创建 3D 文本。 核心代码如下: const loader = new FontLoader();loader.load(textFamily.value, function (font) {…

一套CRM多少钱?

在企业的客户关系管理中&#xff0c;CRM 系统起着至关重要的作用。随着市场上 CRM 系统的种类繁多&#xff0c;其价格也成为企业关注的焦点。那么&#xff0c;一套 CRM 系统究竟需要多少钱呢&#xff1f;这受到多种因素的影响&#xff0c;今天我就来和大家好好聊聊这个问题。大…

Bacnet+springboot部署到linux后,无法检测到网络中的其他设备

场景描述 springbootbacnet4j项目完成后&#xff0c;在window环境可以正常检测到其他设备&#xff0c;但是部署到linux环境之后&#xff0c;无法获取。 解决办法 首先bacnet的子网掩码要设置为&#xff1a;255.255.255.0 确保linux服务器的防火墙允许 255.255.255.255 广播。…

基于springboot的招聘系统的设计与实现

摘 要 随着互联网时代的发展&#xff0c;传统的线下管理技术已无法高效、便捷的管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;国家在工作岗位要求不断提高的前提下&#xff0c;招聘系统建设也逐渐进入了信息化时代。…

STM32(二十一):看门狗

WDG&#xff08;Watchdog&#xff09;看门狗&#xff0c;手动重装寄存器的操作就是喂狗。 看门狗可以监控程序的运行状态&#xff0c;当程序因为设计漏洞、硬件故障、电磁干扰等原因&#xff0c;出现卡死或跑飞现象时&#xff0c;看门狗能及时复位程序&#xff0c;避免程序陷入…

HTML的总结作业

作业1 参照图使用表格定位表单。 参考代码 <!DOCTYPE html> <html> <head> <meta charset"utf-8"/> <title></title> </head> <body> <form action""> …

网上摄影工作室:Spring Boot框架的应用实例

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

SQL-lab靶场less1-4

说明&#xff1a;部分内容来源于网络&#xff0c;如有侵权联系删除 前情提要&#xff1a;搭建sql-lab本地靶场的时候发现一些致命的报错&#xff1a; 这个程序只能在php 5.x上运行&#xff0c;在php 7及更高版本上&#xff0c;函数“mysql_query”和一些相关函数被删除&#xf…