问题标签 [pimpl-idiom]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
1390 浏览

c++ - c++ pimpl idiom : 依赖于模板参数的实现

这个问题中,我没有成功询问如何根据模板参数使用不同的 pimpl 实现。

也许这个例子能更好地说明我正在尝试做的事情:

如果我尝试专门化 struct C,它仍然会失败(以上内容无法编译)

那么,有可能做到吗?

我知道这样的解决方法:

但如果可能的话,我想避免它

0 投票
3 回答
2114 浏览

c++ - C++ pimpl 习惯用法和静态方法和字段

我想更好地了解如何在存在 PIMPL 习语的情况下使用静态字段方法。考虑以下代码。

MyClass.h 文件:

MyClass.cpp 文件:

我有这两个错误:

  1. 不能将成员函数 static_method 声明为具有静态链接
  2. static_field 未在此范围内声明

我对pimpl成语不是很熟悉。

所以我的问题是我如何实现静态方法和字段声明以尊重 PIMPL 习语并成功编译它?

我在这段代码中做错了什么?

我该如何更改我的代码?

0 投票
6 回答
281 浏览

c++ - 如何从类定义中省略私有非虚拟方法?

可以说我有以下内容:

a.hpp:

一个.cpp:

不幸的是,在这种情况下,a.cp​​p 将无法编译,因为“get_complicated()”不是 A 的方法。

所以,我们可以试试这个:

a.hpp:

但随后 a.hpp 无法编译,因为 something_complicated 未定义。

如果它是一个类,我们可以转发声明 something_complicated,但它可能是一个 typedef,所以它已经过时了。

在不公开 b_ 或在 a.hpp 中包含 something_complicated.hpp 的情况下,我能想到的唯一方法如下:

一个.cpp:

当然我不必定义一个宏来解决这个问题?有什么选择吗?

0 投票
4 回答
19929 浏览

c++ - 我应该使用 shared_ptr 还是 unique_ptr

我一直在使用 pimpl 成语制作一些对象,但我不确定是否使用std::shared_ptror std::unique_ptr

我知道这样std::unique_ptr效率更高,但这对我来说不是什么大问题,因为这些对象无论如何都比较重,所以std::shared_ptrover的成本std::unique_ptr相对较小。

我目前std::shared_ptr只是因为额外的灵活性而去。例如,使用 astd::shared_ptr允许我将这些对象存储在 hashmap 中以便快速访问,同时仍然能够将这些对象的副本返回给调用者(因为我相信任何迭代器或引用都可能很快变得无效)。

但是,这些对象实际上并没有被复制,因为更改会影响所有副本,所以我想知道也许使用std::shared_ptr和允许副本是某种反模式或坏事。

它是否正确?

0 投票
2 回答
977 浏览

c++ - pimpl:避免使用 pimpl 指向指针的指针

在这个问题中,我问了“pimpl:shared_ptr 或 unique_ptr”,我确信 pimpl 习语的正确用法是使用 a unique_ptr,而不是 a shared_ptr。它应该对用户起作用,就好像根本没有指针一样,而很明显,shared_ptr在复制时引入了别名,这绝对像一个指针。

因此,假设用户想要为shared_ptr我的 pimpl 对象创建一个(假设他们是否真的想要多个别名)。例如:

这将导致shared_ptr指向unique_ptr我的实现。

如果我能实现以下目标,那就太好了:

但是以某种方式摆脱了指向指针的指针,同时仍然保持 pimpl 的实现隐藏。

任何想法如何实现这一点(我很高兴更改第 (2) 行和显然my_pimpl,但希望第 (3) 和 (4) 行保持不变)。

0 投票
1 回答
405 浏览

c++ - 请求 Pimpl 框架评论/建议

我基本上已经实施了一个提案,我的问题是,它是否已经完成,如果是,在哪里?和/或有更好的方法来做我正在做的事情吗?很抱歉这篇文章的长度,除了提供代码之外,我不知道有更好的方法来解释我的方法。

我之前问过pimpl 的问题:避免使用 pimpl 指向指针?

在这里再次解释这个问题,基本上,假设我们有一个 interfaceinterface和一个 implementation impl。此外,像 pimpl 习惯用法一样,我们希望能够单独编译impl.

现在在 c++0x 中执行此操作的一种方法是unique_ptrinterfacewhich 指向impl. 方法的实际实现interface不包含在其中,它们与接口和实现一起main.cpp单独编译。interface.cppimpl

我们设计这个类,就好像指针不存在一样,因此它对用户有效透明。我们使用.符号来调用方法,而不是->符号,如果我们要复制,我们实现深拷贝原理图。

但后来我在想,如果我真的想要一个指向这个 pimpl 的共享指针怎么办。我可以这样做shared_ptr<interface>,但后来我有一个 shared_ptr 到一个 unique_ptr,我认为这有点傻。我可以使用shared_ptr而不是unique_ptrinside interface,但它仍然会使用.符号调用函数,并且看起来不像指针,所以当它浅拷贝时可能会让用户感到惊讶。

我开始认为最好有一些通用模板类来连接接口和任何兼容的and对的X相应实现,处理大量 pimpl 样板文件。YXY

所以下面是我试图做到的方式。

首先,我将从main.cpp

基本上在这里,x1是标准的unique_ptrpimpl 实现。x2实际上是 a shared_ptr,没有 a 引起的双指针unique_ptr。许多分配和构造函数仅用于测试。

现在interface.hpp

interface_macros.hpp

interface_macros.hpp只包含我开发的框架所需的一些样板代码。该接口HANDLER作为模板参数并使其成为基类,此构造函数只是确保将事物转发到HANDLER动作发生的基类。当然,interface它本身不会有任何成员,也没有构造函数,因为它是故意的,只有一些公共成员函数。

现在interface.cpp是我们的另一个文件。它实际上包含 的实现interface,尽管它的名字,也包含 的接口和实现impl。我不会完整列出该文件,但首先认为它包含的是interface_impl.hpp(抱歉命名混乱)。

这里是interface_impl.hpp

注意get_impl()方法调用。这将由HANDLER稍后提供。

impl.hpp包含的接口和实现impl。我本可以将这些分开,但没有看到需要。这里是impl.hpp

现在让我们来看看unique_pimpl.hpp。请记住,这包含在 中main.cpp,因此我们的主程序对此进行了定义。

unique_pimpl.hpp

在这里,我们将传递模板类INTERFACE(它有一个参数 ,HANDLER我们将在这里用 填充unique_pimpl)和IMPL类(在我们的例子中是impl)。此类是unique_ptr实际所在的位置。

现在,这里提供了get_impl()我们正在寻找的功能。我们的接口可以调用这个函数,这样它就可以将调用转发给实现。

让我们看看unique_pimpl_impl.hpp

现在上面的很多只是样板代码,并且可以满足您的期望。create(...)简单地转发给 的构造函数impl,否则用户将看不到它。还有一个宏定义DEFINE_UNIQUE_PIMPL,我们稍后可以使用它来实例化适当的模板。

现在我们可以回到interface.cpp

这确保编译所有适当的模板,instantate_my_unique_pimpl_create_functions()确保我们编译一个 0 参数创建,否则永远不会被调用。如果impl有其他我们想从 main 调用的构造函数,我们可以在这里定义它们(例如my_unique_pimpl::create(int(0)))。

回头看看main.cpp,您现在可以看到如何unique_pimpl创建 s。但是我们可以创建其他加入方法,这里是shared_pimpl

shared_pimpl.hpp

shared_pimpl_impl.hpp

请注意,createforshared_pimpl实际上返回一个 real shared_ptr,没有双重重定向。中的 static_castget_impl()是一团糟,遗憾的是我不知道更好的方法,除了在继承树上走两步,然后再往下走两步到实现。

例如,我可以想象为侵入式指针制作其他“HANDLER”类,甚至是一个简单的堆栈分配连接,它需要以传统方式包含所有头文件。这样,用户可以编写 pimpl 就绪但不需要 pimpl 的类。

您可以从此处的 zip 文件中下载所有文件。他们将解压到当前目录。您需要使用具有一些 c++0x 功能的东西进行编译,gcc 4.4.5 和 gcc 4.6.0 对我来说都很好。

所以就像我说的,任何建议/意见都将不胜感激,如果这已经完成(可能比我做得更好),如果你能指导我,那就太好了。

0 投票
5 回答
1908 浏览

c++ - pimpl 与匿名命名空间兼容吗?

我正在尝试使用pimpl模式并在匿名命名空间中定义实现类。这在 C++ 中可能吗?我的失败尝试如下所述。

是否可以在不将实现移动到具有名称(或全局名称)的名称空间中的情况下解决此问题?

0 投票
7 回答
4992 浏览

c++ - 在不使用未命名命名空间的情况下将 C++ 类隐藏在标头中

我正在编写一个 C++ 头文件,我在其中定义了一个

我想对外界隐藏(因为它可能会在此标头的未来版本中更改甚至被删除)。

在同一个头文件中还有一个 B 类,它有一个 A 类的对象作为成员:

向外界隐藏 A 级的正确方法是什么?

如果我将 A 的定义放在一个未命名的命名空间中,编译器会发出警告,所以我假设,由于内部链接的问题,我应该做其他事情。

0 投票
2 回答
315 浏览

c++ - 如何正确包装 3rd 方库结构?

在我的项目中,我使用了一个不断变化的 3rd 方库。我有这个库的包装类(桥模式 + Pimpl 模式)。因此,除了包装器实现之外,我的任何来源都没有看到该库。这个库有一个 Options 结构,例如

我希望这个结构在 GUI 模块中可用,以构建一个允许设置这些选项的对话框。我需要为它创建一个包装结构吗?例如

或者我应该直接将该结构标头包含到我的源代码中吗?

包装器的缺点是:复制粘贴,用于在结构之间转换的附加代码。直接的缺点包括:打破 pimpl 成语。

这个问题可能还有其他解决方案吗?

另外我想强调的是,第 3 方库是不断变化的,所以我必须采用我的资源来支持库的每个新版本。

0 投票
4 回答
334 浏览

c++ - 一种更简单的 pimpl 形式

为什么不选择这个设计:

而不是这个:

我可以隐藏实现细节并使用源文件中定义的变量和静态函数加速编译吗?如果不是,这个设计有什么问题(除了继承)?