热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++ pimpl机制详细讲解

PIMPL 是 C++ 中的一个编程技巧,意思为指向实现的指针。具体操作是把类的实现细节放到一个单独的类中,并用一个指针进行访问

源码仓库

什么是PImpl机制

Pointer to implementation(PImpl ),通过将类的实现细节放在一个单独的类中,从其对象表示中删除它们,通过一个不透明的指针访问它们(cppreference 是这么说的)

通过一个私有的成员指针,将指针所指向的类的内部实现数据进行隐藏

class Demo {
public:
	...
private:
	DemoImp* imp_;
}

为什么用PImpl 机制

个人拙见

  • C++ 不像Java 后端型代码,能有行业定式的列目录名形成规范(controller、Dao等)
  • 隐藏实现,降低耦合性和分离接口(隐藏类的具体实现)
  • 通过编译期的封装(隐藏实现类的细节)

业界实现

优秀开源代码有实现

PImpl实现

方法一

cook_cuisine.h

#pragma once
#include 
#include 
#include 
//  Pointer to impl ementation
class CookImpl;
// 后厨
class Cook {
public:
    Cook(int, const std::vector&);
    ~Cook();
    std::vector getMenu();     /* 获取菜单 */
    uint32_t getChefNum();                  /* 获取厨师数量 */
private:
    CookImpl* impl_;
};
typedef std::shared_ptr CookPtr;		// 美妙的typedef 懒人工具

cook_cuisine.cc

#include "cook_cuisine.h"
class CookImpl {
public:
    CookImpl(uint32_t checf_num, const std::vector& menu):checf_num_(checf_num), menu_(menu) {}
    std::vector getMenu();
    uint32_t getChefNum();
private:
    uint32_t checf_num_;
    std::vector menu_;
};
std::vector CookImpl::getMenu() {
    return menu_;
}
uint32_t CookImpl::getChefNum() {
    return checf_num_;
}
Cook::Cook(int chef_num, const std::vector& menu) {
    impl_ = new CookImpl(chef_num, menu);
}
Cook::~Cook() {
    delete impl_;
}
std::vector Cook::getMenu() {
    return impl_->getMenu();
}
uint32_t Cook::getChefNum() {
    return impl_->getChefNum();
}

方法二

cook_cuisine.h

#pragma once
#include 
#include 
#include 
#include "cook_cuisine_imp.h"
// 后厨
class Cook {
public:
    Cook(int, const std::vector&);
    ~Cook();
    std::vector getMenu();     /* 获取菜单 */
    uint32_t getChefNum();                  /* 获取厨师数量 */
private:
    CookImplPtr impl_;
};
typedef std::shared_ptr CookPtr;

cook_cuisine.cc

#include "cook_cuisine.h"
Cook::Cook(int chef_num, const std::vector& menu) {
    impl_.reset(new CookImpl(chef_num, menu));
}
Cook::~Cook() {
}
std::vector Cook::getMenu() {
    return impl_->getMenu();
}
uint32_t Cook::getChefNum() {
    return impl_->getChefNum();
}

cook_cuisine_imp.h

#pragma once
#include 
#include 
#include 
class CookImpl {
public:
    CookImpl(uint32_t checf_num, const std::vector& menu):checf_num_(checf_num), menu_(menu) {}
    std::vector getMenu();
    uint32_t getChefNum();
private:
    uint32_t checf_num_;
    std::vector menu_;
};
typedef std::shared_ptr CookImplPtr;

cook_cusine_imp.cc

#include "cook_cuisine_imp.h"
std::vector CookImpl::getMenu() {
    return menu_;
}
uint32_t CookImpl::getChefNum() {
    return checf_num_;
}

main.cc

#include "cook_cuisine.h"
#include 
using namespace std;    // Testing, 平时开发可千万别用这句
int main() {
    int checf_num = 10;
    const std::vector menus = { "Chicken", "Beef", "Noodle", "Milk" };
    CookPtr cook(new Cook(checf_num, menus));
    auto cook_menu = cook->getMenu();
    auto cook_checf_num = cook->getChefNum();
    cout <<"======================Chinese Cook======================\n";
    cout <<"============Checf: " <

CMakeLists.txt

mkdir build
cd build
cmake ..

PImpl 缺点

空间开销:每个类都需要额外的指针内存指向实现类

时间开销:每个类间接访问实现的时候多一个间接指针操作的开销

阅读开销:使用、阅读和调试上带来一些不便(不是啥问题)

总结

每种设计方法都有它的优点和缺点

PImpl 用一些内存空间和额外类的实现换取耦合性的下降,是可以接受的

但重点在:在性能/内存要求不敏感处,PImpl 技术才更优不错的发挥舞台

极端例子:

你不可能在斐波那契的实现中还加个PImpl 机制,多此一举

到此这篇关于C++ pimpl机制详细讲解的文章就介绍到这了,更多相关C++ pimpl机制内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 在尝试加载支持推送通知的iOS应用程序的Ad Hoc构建时,遇到了‘no valid aps-environment entitlement found for application’的错误提示。本文将探讨此错误的原因及多种可能的解决方案。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 本文通过分析一个具体的案例,探讨了64位Linux系统对32位应用程序的兼容性问题。案例涉及OpenVPN客户端在64位系统上的异常行为,通过逐步排查和代码测试,最终定位到了与TUN/TAP设备相关的系统调用兼容性问题。 ... [详细]
  • 本文通过C++语言实现了一个递归算法,用于解析并计算数学表达式的值。该算法能够处理加法、减法、乘法和除法操作。 ... [详细]
  • 本文详细介绍了JQuery Mobile框架中特有的事件和方法,帮助开发者更好地理解和应用这些特性,提升移动Web开发的效率。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 本文详细介绍了C++中的构造函数,包括其定义、特点以及如何通过构造函数进行对象的初始化。此外,还探讨了转换构造函数的概念及其在不同情境下的应用,以及如何避免不必要的隐式类型转换。 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • 解决JavaScript中法语字符排序问题
    在开发一个使用JavaScript、HTML和CSS的Web应用时,遇到从SQLite数据库中提取的法语词汇排序不正确的问题,特别是带重音符号的字母未按预期排序。 ... [详细]
  • importjava.io.*;importjava.util.*;publicclass五子棋游戏{staticintm1;staticintn1;staticfinalintS ... [详细]
  • 高级缩放示例.就像谷歌地图一样.它仅缩放图块,但不缩放整个图像.因此,缩放的瓷砖占据了恒定的记忆,并且不会为大型缩放图像调整大小的图像.对于简化的缩放示例lookhere.在Win ... [详细]
  • 深入理解Java SE 8新特性:Lambda表达式与函数式编程
    本文作为‘Java SE 8新特性概览’系列的一部分,将详细探讨Lambda表达式。通过多种示例,我们将展示Lambda表达式的不同应用场景,并解释编译器如何处理这些表达式。 ... [详细]
  • 本文详细介绍了如何在Windows操作系统中配置和使用Lex(Flex)与Yacc(Bison),包括软件的下载、安装以及通过示例验证其正确性的步骤。 ... [详细]
author-avatar
手机用户2602915825_387
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有