首页 / 知识
关于c ++:为什么应使用“ PIMPL”这一成语?
2023-04-15 05:18:00

Why should the “PIMPL” idiom be used?本问题已经有最佳答案,请猛点这里访问。
背景资料: PIMPL成语(实现的指针)是一种用于隐藏实现的技术,其中,公共类包装了公共类所属的库外部看不到的结构或类。 这对库用户隐藏了内部实现细节和数据。 当实现这个习惯用法时,为什么将公共方法放在pimpl类上而不放在公共类上,因为公共类方法的实现将被编译到库中,并且用户只有头文件?
为了说明这一点,此代码将 为什么不直接在公共课上实施Purr?
我认为大多数人将此称为"句柄主体"成语。请参阅James Coplien的书《高级C ++编程样式和习语》(Amazon链接)。它也被称为柴郡猫(Cheshire Cat),因为刘易斯·卡洛尔(Lewis Caroll)的性格逐渐消失,直到只有咧嘴笑为止。 示例代码应分布在两组源文件中。然后只有Cat.h是产品随附的文件。 CatImpl.h包含在Cat.cpp中,而CatImpl.cpp包含CatImpl :: Purr()的实现。使用您的产品的公众看不到它。
基本上,这个想法是让尽可能多的实现隐藏起来。 为此,我们在2000年重写了IONAs Orbix 3.3产品。 正如其他人所提到的,使用他的技术可以将实现与对象的接口完全分离。这样,如果您只想更改Purr()的实现,则不必重新编译使用Cat的所有内容。 这项技术用于称为"按合同设计"的方法中。
为了有价值,它将实现与接口分离。在小型项目中,这通常不是很重要。但是,在大型项目和库中,可以使用它来显着减少构建时间。
考虑到
我正在开发一个用于非线性优化的库(请阅读"很多讨厌的数学"),该库是在模板中实现的,因此大多数代码都在标头中。编译(在不错的多核CPU上)大约需要五分钟,而仅在空白的 它与保护实现不受其他公司复制并不一定有任何关系-除非您可以从成员变量的定义中猜出算法的内部工作原理,否则无论如何都不会发生(如果是,则为可能不是很复杂,一开始就不值得保护)。 如果您的班级使用pimpl习惯用法,则可以避免在公共班级上更改头文件。 这使您可以在pimpl类中添加/删除方法,而无需修改外部类的头文件。您也可以在pimpl中添加/删除#includes。 更改外部类的头文件时,必须重新编译包含它的所有内容(如果其中任何一个是头文件,则必须重新编译包含它们的所有内容,依此类推) 通常,在Owner类(在本例中为Cat)的标头中,对Pimpl类的唯一引用将是前向声明,就像您在此处所做的那样,因为这样可以大大减少依赖性。 例如,如果您的Pimpl类具有ComplicatedClass作为成员(而不仅仅是指针或对其的引用),则在使用ComplicatedClass之前,需要对其进行完全定义。实际上,这意味着包括" ComplicatedClass.h"(它还将间接包括ComplicatedClass所依赖的任何内容)。这可能导致单个标头填充会引入很多东西,这对于管理依赖项(以及编译时间)是不利的。 使用pimpl idion时,只需#include所有者类型(此处为Cat)的公共接口中使用的内容。这对使用您的图书馆的人来说使事情变得更好,并且意味着您不必担心图书馆的内部某些部分的人-是由于错误,还是因为他们想做您不允许做的事情,所以他们#define包括您的文件之前为私人公开。 如果这是一个简单的类,通常没有理由使用Pimpl,但是对于类型很大的时候,这可能是一个很大的帮助(尤其是避免长时间的构建) 好吧,我不会使用它。我有一个更好的选择: foo.h:
foo.cpp:
这个图案有名字吗? 作为Python和Java程序员,我比pImpl习惯更喜欢它。 我们使用PIMPL习惯用法来模拟面向方面的编程,其中在执行成员函数之前和之后分别调用pre,post和error方面。
我们还使用指向基类的指针在许多类之间共享不同方面。 这种方法的缺点是库用户必须考虑将要执行的所有方面,但只能看到其类。 它需要浏览文档中是否有任何副作用。 将对impl-> Purr的调用放在cpp文件中意味着,将来您可以做完全不同的事情而不必更改头文件。也许明年他们会发现可以调用的辅助方法,因此可以更改代码以直接调用该方法,而根本不使用impl-> Purr。 (是的,他们也可以通过更新实际的impl :: Purr方法来实现相同的目的,但是在这种情况下,您会陷入额外的函数调用,而该函数调用只能依次调用下一个函数什么也没有实现) 这也意味着标头仅具有定义,并且没有任何实现更清晰分隔的实现,这是习惯用法的全部重点。 在过去的几天里,我刚刚实施了我的第一届pimpl课。我用它来解决我在Borland Builder中包含winsock2.h时遇到的问题。这似乎搞砸了结构对齐,并且由于我在类私有数据中有套接字内容,因此这些问题已蔓延到任何包含标头的cpp文件中。 通过使用pimpl,winsock2.h仅包含在一个cpp文件中,在这里我可以控制问题,而不用担心它会再次咬住我。 为了回答原始问题,我发现将呼叫转发到pimpl类的好处是pimpl类与您在插入pimpl类之前的原始类相同,而且实现没有分散到2个对象上以一些奇怪的方式上课。让公众直接进入pimpl类更加清晰。 就像Nodet先生所说的那样,一堂课,一项责任。 我发现这说明了尽管pimpl惯用语非常有名,但我并不认为它在现实生活中经常出现(例如在开源项目中)。 我经常想知道这些"好处"是否夸大了;是的,您可以使一些实现细节更加隐蔽,是的,可以在不更改标题的情况下更改实现,但是实际上这些并不是很大的优势。 就是说,尚不清楚是否需要对实现进行很好的隐藏,而且人们很少真正只更改实现,这很罕见。例如,一旦需要添加新方法,就需要更改标题。 我不知道这是否值得一提,但... 是否有可能在自己的名称空间中实现,并为用户看到的代码提供公共包装器/库名称空间:
这样,所有库代码都可以利用cat名称空间,并且由于需要向用户公开类,因此可以在catlib名称空间中创建包装器。 |
最新内容
相关内容
linux命令大全数据库?
linux命令大全数据库?,服务,系统,平台,状态,软件,通用,环境,数据,神州,地址,在Linux上用命令怎么连接数据库(linux连接oracle数据库命令)登录linux上数据库的命令?
linux上数据库的命令?,服务,系统,信息,地址,命令,密码,工具,管理,数据,单位,在Linux上用命令怎么连接数据库(linux连接oracle数据库命令)1、登linux命令dm数据库?
linux命令dm数据库?,地址,软件,时间,设备,名字,服务,位置,名称,公司,命令,linux创建dm数据库超时linux/sys下无法新建 方法如下打开c盘,在用户linux文件结构命令?
linux文件结构命令?,系统,数字,技术,设备,传播,第一,管理,数据,发展,目录,Linux目录结构也就是说,Linux下只有一个单独的树状结构。而在微软操linux使用命令的方法?
linux使用命令的方法?,系统,信息,工具,标准,数据,命令,左下角,目录,文件夹,图标,linux的cd命令的使用方法1、cd ~:回到用户家目录。注:这得看你linux目录结构树命令?
linux目录结构树命令?,系统,工作,信息,数据,设备,管理,目录,发展,时间,结构,Linux系统常用操作命令有哪些1、linux常用命令: pwd命令 该命令linux存储数据命令?
linux存储数据命令?,系统,管理,数据,设备,情况,地址,工作,命令,服务,平台,Linux文件系统操作命令1、cat:可以显示文件的内容(经常和more搭配使linux数据库查找命令?
linux数据库查找命令?,位置,名称,状态,服务,软件,信息,系统,命令,名字,密码,在linux中如何用命令查找文件在哪使用查找命令 “find”命令允许linux数据库同步命令?
linux数据库同步命令?,信息,系统,汽车,车辆,服务,工作,通信,一致,分析,数据,DB2数据库在linux操作系统的指令有哪些?1、linux系统常用操作命令linux建立数据库命令?
linux建立数据库命令?,软件,系统,工作,数据,密码,工具,数据库,一致,网络,服务,linux中在shell中怎么创建一个数据库1、以下的文章主要讲述的是linux命令进数据库?
linux命令进数据库?,地址,系统,名字,服务,密码,命令,读法,数据库,操作系统,主机,linux系统mysql数据库怎么进入数据库首先确保linux下mysql安linux查询表结构命令?
linux查询表结构命令?,系统,标准,信息,数据,地址,设备,时间,适当,软件,命令,linux下怎么用tree命令以树形结构显示文件目录结构1、以Ubuntu为