C++程序设计机制:pimpl机制

2023-11-02

1、pimpl机制的作用

pimpl(private implementation)其主要作用是解开类的使用接口和实现的耦合。

关于耦合性:耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。

模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差。

软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。

2、pimpl机制的实现思想

pimpl(private implementation)的思想是将私有的数据和函数放入一个单独的类中,并保存在一个实现文件中,然后在使用它的头文件中对这个类进行前置类型声明,并定义一个指向该实现类的指针。类的构造函数分配这个pimpl类,而析构函数则释放它。这样可以解开类的使用接口和实现的耦合。

3、实际项目开发遇到的问题

有时候需要修改某个类的实现,而这样的修改会导致所有包含该类的代码需要重新编译,当这个类在项目中被大量使用时,那么编译时间是很长的;别人使用“不合法的方法”调用了我们编写的接口,突破了我们期望给予的限制。

使用pimpl能给我们带来的好处:
1.将具体类的实现封装到另一个类中,使用者只能看到一个前置类型声明和对应的指针。除非使用者去修改对应的实现,否则,他将无法知道具体的实现,也就无法通过一些非法的方式去访问。从一定程度上防止了封装的泄漏;
2.同时类与数据成员之间的耦合最低,类看起来总是一个样子,包含该类声明的文件也不会因为类实现的改变而重新编译,节约编译时间。

4、案例:暴露私有实现

cmessage.h:

#ifndef __MESSAGE_H__
#define __MESSAGE_H__

#include <string>

class CMessage
{
public:
CMessage(std::string strWarn);
~CMessage();
void printf();

private:
std::string m_strWarnMsg;
};

#endif //#ifndef __MESSAGE_H__

这是一个消息类,提供消息打印方法。

但是当我们提供该头文件的时候,其实已经暴露了私有的实现。

5、案例:修改实现,导致大量源文件重新编译

cmessage.h:

#ifndef __MESSAGE_H__
#define __MESSAGE_H__

#include <string>

class CMessage
{
public:
CMessage(std::string strWarn);
~CMessage();
void printf();

private:
std::string m_strWarnMsg;
std::string m_strAdditionMsg;//新功能
};

虽然之前的接口没有改变,但是项目中使用到该头文件的所有源码文件都需要重新编译。

6、案例:使用pimpl思想重新设计模块

使用上面提到的pimpl(private implementation)的思想。我们重新设计该类的实现。

cmessage.h:

#ifndef __MESSAGE_H__
#define __MESSAGE_H__

#include <string>

class CMessagePrivate;//实现类前置类型声明
class CMessage
{
public:
CMessage(std::string strWarn);
~CMessage();
void printf();

private:
CMessagePrivate * const d;//实现类指针
};
#endif //#ifndef __MESSAGE_H__

cmessage.cpp:

#include "cmessage.h"
#include "cmessage_p.h"

CMessage::CMessage(std::string strWarn):d(new CMessagePrivate(strWarn))
{
	
}

CMessage::~CMessage()
{
	delete d;
}

void CMessage::printf()
{
	d->printf();
}

cmessage_p.h:

#ifndef __MESSAGE_P_H__
#define __MESSAGE_P_H__

#include <string>

class CMessagePrivate
{
public:
CMessagePrivate(std::string strWarn);
~CMessagePrivate();
void printf();

private:
std::string m_strWarnMsg;
std::string m_strAdditionMsg;
int m_fileNo;
};

#endif //#ifndef __MESSAGE_P_H__

cmessage_p.cpp:

#include "cmessage_p.h"
#include <iostream>


CMessagePrivate::CMessagePrivate(std::string strWarn):m_strWarnMsg(strWarn),m_strAdditionMsg(__FILE__),m_fileNo(__LINE__)
{
	
}

CMessagePrivate::~CMessagePrivate()
{

}

void CMessagePrivate::printf()
{
	std::cout << m_strWarnMsg << std::endl;
	std::cout << m_strAdditionMsg << ":" << m_fileNo << std::endl;
}

此时,CMessage类还是提供同样的接口printf,只是该接口的实现放到了CMessagePrivate类中实现了,对于使用者毫不知情。

还有,在CMessagePrivate类中任何新加的功能,都只会影响到CMessagePrivate.cpp和CMessage.cpp,任何包含cmessage.h文件的源文件都不需要重新编译,大大节省了项目编译的时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++程序设计机制:pimpl机制 的相关文章

随机推荐

  • 使用R语言对指定列进行开根号并生成新的数据列

    使用R语言对指定列进行开根号并生成新的数据列 在R语言中 我们经常需要对数据进行各种数学运算和转换 其中一项常见的操作是对指定列进行开根号并生成新的数据列 本文将介绍如何使用R语言实现这个操作 假设我们有一个名为 data 的数据框 其中包
  • Sublime Text入门使用教程

    简介 说到最好用的编辑器 首推Sublime 感觉比notepad 胜出无数倍 支持 Windows 及 Mac 等多平台 类似于 Eclipse IDEA 有着丰富的插件系统 完全可以满足各种编辑 开发需求 强烈建议安装或者升级到最新版
  • boost解析xml C++

    cpp include
  • 【Xilinx Vivado时序分析/约束系列2】FPGA开发时序分析/约束-建立时间

    目录 基本概念 数据结束时间 Data finish time 保持时间门限 保持时间余量 Hold Slack 基本概念 数据结束时间 Data finish time 之前解释了数据达到的时间 对于data arrival time T
  • 理解矩阵(一)

    前不久chensh出于不可告人的目的 要充当老师 教别人线性代数 于是我被揪住就线性代数中一些务虚性的问题与他讨论了几次 很明显 chensh觉得 要让自己在讲线性代数的时候不被那位强势的学生认为是神经病 还是比较难的事情 可怜的chens
  • 区间预测

    区间预测 MATLAB实现QRCNN LSTM卷积长短期记忆神经网络分位数回归时间序列区间预测 目录 区间预测 MATLAB实现QRCNN LSTM卷积长短期记忆神经网络分位数回归时间序列区间预测 效果一览 基本介绍 模型描述 程序设计 参
  • 线扫激光算法原理

    一 线扫激光算法原理 激光器发出的激光束经准直聚焦后垂直入射到物体表面上 表面的散射光由接收透镜成像于探测器的阵列上 光敏面于接收透镜的光轴垂直 如图 当被测物体表面移动x 反应到光敏面上像点位移为x a为接收透镜到物体的距离 物距 b为接
  • 《html学习笔记》列表与表单

    目录 1 列表 1 1列表分为三种 无序 有序 自定义 1 2 无序列表 1 3 有序列表 1 4 自定义列表 2 表单 2 1 表单域 2 2 表单控件 2 3 常用属性 2 4下拉列表 2 5标签 2 6文本域 1 列表 1 1列表分为
  • js两数之和

    两数之和 力扣 第一题 给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 数组nums nums 2 7 11 15 target 值是 tar
  • WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制

    WebRTC音视频通话 新增或修改SDP中的码率Bitrate限制参数 之前搭建ossrs服务 可以查看 https blog csdn net gloryFlow article details 132257196 之前实现iOS端调用o
  • SOA微服务案例springboot+mybatis使用gradle构建案例

    SOA系统架构的体现之springboot mybatis框架 题外话 为什么要选用SOA架构 不同种类的操作系统 应用软件 系统软件和应用基础结构 application infrastructure 相互交织 这便是IT企业的现状 一些
  • Java中Integer.valueOf()解读

    我们先看一段代码 public static void main String args Integer i1 20 Integer i2 20 System out println i1 i2 System out println i1
  • java基础实验:定义一个学生类Student,该类中包含的属性有:姓名、性别、高数成绩、线代成绩、C语言成绩等

    Java基础实验 目录 一 实验内容 二 实验过程 1 实验代码 2 实验截图 总结 前言 继续java基础实验的练习 虽然这个实验明明更先完成 这个实验用于输入输出学生基本信息 创建学生类调用函数完成成绩的录入 输出 求平均值等功能 一
  • 采用VMD按照某一坐标轴旋转坐标结构

    关注 M r m a t e r
  • win10 视频合并

    首先打开cmd 然后切换到F盘Media目录 输入命令 copy b f hello mp4回车键 如下图 copy b luanlun QvqYNhrj hello mp4
  • 新手玩转Linux Kernel漏洞之Null Pointer Dereference

    新手玩转Linux Kernel漏洞之Null Pointer Dereference 前言 这是我内核漏洞的入门篇 不是很复杂 希望能给徘徊在门外的小伙伴一点启发 漏洞描述 A NULL pointer dereference occur
  • Hash散列 开放定址法与链地址法

    假设一个数组中表示位置key 0 1 2 3 4 5 6 对应存储的哈希函数为hash key H key的个数为m 开放定址法 H di m 1 线性探测再散列 H i m i 0 1 2 m 1 即di为1 2 3 4 5 6 2 平方
  • C++ 容器中自定义类型 value_type

    现在来看看value type到底有什么用 首先定义两个包装容器 只是对任意类型的值进行了一层包装而已 template
  • python中if __name__='__main__':的解析

    当你打开一个 py文件时 经常会在代码的最下面看到if name main 模块是对象 并且所有的模块都有一个内置属性 name 一个模块的 name 的值取决如何应用模块 如果 import 一个模块 那么模块 name 的值通常为模块文
  • C++程序设计机制:pimpl机制

    1 pimpl机制的作用 pimpl private implementation 其主要作用是解开类的使用接口和实现的耦合 关于耦合性 耦合性 Coupling 也叫耦合度 是对模块间关联程度的度量 耦合的强弱取决于模块间接口的复杂性 调