这个问题已经有一个答案在这里:

背景资料:

PIMPL成语 (针来实现)是一个技术执行情况隐藏在哪一个公共类包装了一个结构或类无法看到外面的图书馆公共类的一部分。

这种隐藏的内部执行情况的详细信息和数据从用户的图书馆。

在实现这个成语为什么你地方的公共方法上的pimpl类和不公类由于公共类方法的实现将编制成图书馆和用户的只有头文件?

为了说明,这个代码把 Purr() 执行在实施类和包装它。

为什么不执行的呼噜声直接在公共课吗?

// header file:
class Cat {
    private:
        class CatImpl;  // Not defined here
        CatImpl *cat_;  // Handle

    public:
        Cat();            // Constructor
        ~Cat();           // Destructor
        // Other operations...
        Purr();
};


// CPP file:
#include "cat.h"

class Cat::CatImpl {
    Purr();
...     // The actual implementation can be anything
};

Cat::Cat() {
    cat_ = new CatImpl;
}

Cat::~Cat() {
    delete cat_;
}

Cat::Purr(){ cat_->Purr(); }
CatImpl::Purr(){
   printf("purrrrrr");
}
有帮助吗?

解决方案

  • 因为你想 Purr() 为了能够使用私人成员 CatImpl. Cat::Purr() 不会允许这样一种访问没有 friend 《宣言》。
  • 因为你那就不要混合责任:一个类实现,一个类转发。

其他提示

我想大多数人称之为处理体成语。见詹姆斯Coplien的书先进C++编程的风格和语(亚马逊的链接).它也被称为 柴郡猫 因为刘易斯卡罗尔的角色,逐渐褪去,直至只有笑容仍然存在。

例码应该可以分布在两个组源文件。那只猫。h是该文件是附带产物。

CatImpl.h包括通过Cat.cpp 和CatImpl.cpp 包含的执行CatImpl::呼噜().这将不会是可见的公众使用的产品。

基本的想法是要隐藏尽可能执行从窥视的眼睛。这是最有用的,在那里你有一个商业产品,是运行一系列的图书馆是通过访问API客户的代码编制,反对和链接。

我们这样做是与改写伊奥纳斯Orbix3.3产品在2000年。

正如其他人,用他的技术完全分离的执行情况的口的对象。然后你会不会重新编译的一切使用的猫如果你只是想要改变的执行情况的呼噜声().

这种技术是使用一种方法称为 设计合同.

为什么是值得的,它分离的执行情况的接口。这通常不是非常重要的小型项目。但是,在大型项目和图书馆,它可以用来减少建设时间显着。

考虑执行情况 Cat 可以包括许多标题,可能涉及的模板元编程,需要时间来编译自己。为什么要用户,他们只是想要使用 Cat 必须包括所有的吗?因此,所有必要的文件被隐藏,使用pimpl语(因此前的声明 CatImpl),并使用的接口不力的用户,包括他们。

我正在开发一个库,用于非线性优化(阅读"很多讨厌数学"),这是实施模板,因此大多数代码头。它大约需要五分钟汇编(上一个体面的多核CPU),只是分析的标题,在一个否则是空的 .cpp 需要大约一分钟。因此,任何人使用的图书馆已经等待了几分钟,每次他们编译他们的代码,这使得发展的相当 繁琐的.然而,通过隐藏的执行情况和标题,一个只包括一个简单的界面文件,该文件汇编。

它并不一定有任何与保护执行复制通过其他公司-这不可能发生,无论如何,除非内部运作的你的算法可猜测到,从该定义的部件的变量(如果是这样,它可能不是非常复杂,不值得保护的第一个地方)。

如果您类使用pimpl成语,可以避免更改标题的文件在公共类。

这可以让你加入/消除方法的pimpl类,无需修改外部类的标题的文件。你也可以加入/消除#包括向pimpl。

当你改变的外部类的头文件中,你要重新编译的一切#包括它(如果任何这些标题的文件,你要重新编译的一切#包括他们,等等)

通常,只有参考Pimpl类的头为所有人类(Cat在这种情况下)将一向宣言,因为你们在这里完成,因为这可以大大减少依赖性。

例如,如果你Pimpl类具有ComplicatedClass作为一个成员(而不仅仅是一个指针或参考),那么你就需要有ComplicatedClass完全确定之前使用。在实践中,这意味着包括"ComplicatedClass.h"(这也将间接地包括什么ComplicatedClass取决)。这可能导致一个单一的标题填补拉在很多很多的东西,这是不好的管理依赖关系(和你的编次)。

当你使用pimpl idion,你只需要#包括的东西用在公共界面拥有者的类型(其中将猫)。这让事情更好地为人们使用你的图书馆,意味着你不需要担心的人,取决于一些内部的一部分库-无论是错误的,或者是因为他们想要做一些你不允许这样他们#define私人公众面前,包括文件。

如果它是一个简单的类,通常没有理由使用Pimpl,但是对于时候的类型是相当大,它可以是一个很大的帮助(尤其是在避免长建立次)

好吧,我不会使用它。我有个更好的选择:

foo。h:

class Foo {
public:
    virtual ~Foo() { }
    virtual void someMethod() = 0;

    // This "replaces" the constructor
    static Foo *create();
}

foo.cpp:

namespace {
    class FooImpl: virtual public Foo {

    public:
        void someMethod() { 
            //....
        }     
    };
}

Foo *Foo::create() {
    return new FooImpl;
}

不这个模式有一个名字?

作为一个还Python和爪哇的程序员,我喜欢这个了很多比pImpl成语。

我们使用PIMPL成语,以模拟方面导向的编程在预、邮政和错误的方面是称之前和之后的执行的一个部件的功能。

struct Omg{
   void purr(){ cout<< "purr\n"; }
};

struct Lol{
  Omg* omg;
  /*...*/
  void purr(){ try{ pre(); omg-> purr(); post(); }catch(...){ error(); } }
};

我们还使用的指针为基类分享的不同方面之间的许多课程。

这种方式的缺陷是,图书馆用户有考虑到所有方面,将要被执行,但是只能看到他类。它需要浏览该文件的任何副作用。

致电到实施->的呼噜声内的加拿大养恤金计划的文件意味着,在未来你可以做一些完全不同的东西,而不必更改标题的文件。也许明年他们发现一个辅助方法,他们可以打电话,而不是使他们能够改变码通话,直接和不使用实施->的呼噜声。(是的,他们可以实现同样的事情,通过更新的实际实施::呼噜声的方法,但在这种情况下你是坚持一个额外的功能的电话,实现了什么,但调用的下一个功能反过来)

它还指标题仅有的定义并不具有任何实现这使得一个清洁的分离,这是整点的成语。

我只是执行我的第一pimpl类在过去的几天。我用它来消除问题,我有包括winsock2.h在Borland建设者。它似乎是搞砸了对准结构,并因为我已经插的东西在类私人数据,这些问题是扩展到任何cpp文件,其中包括头部。

通过使用pimpl,winsock2.h包括在只有一个cpp文件里,我可以盖上的问题,而不用担心,它会回来咬我。

回答问题的答案,优势在我发现在转发的电话pimpl类是,pimpl类是相同的,为什么你原来的级会已经在你之前pimpl会,再加上你的实现不扩散过2类在一些奇怪的方式。这是很清楚的实现公众简单地向pimpl类。

像先生Nodet所述,一级,一个责任。

我不知道如果这是一个差别值得一提的但是...

将它可能拥有执行其自己的名字空间的和具有公共wrapper/图书馆的名字空间的用于代码用户看到:

catlib::Cat::Purr(){ cat_->Purr(); }
cat::Cat::Purr(){
   printf("purrrrrr");
}

这样,所有图书馆的代码可以使用的猫的名字空间,并需要获得一类的用户出现了一个包装,可以建立在catlib名字空间。

我发现它说的是,尽管在如何知名的pimpl谚语是说,我看不到它作物经常在现实生活中的(例如在开源的项目)。

我常常在想,如果"好处"是夸大其词;是的,你可以把你的一些执行细节,甚至是更隐蔽的,是的,你可以改变你的实施没有改变头,但它并不显而易见,这些都是重大优点在现实。

这就是说,它不清楚的是,没有任何需要你执行 隐藏的很好,也许这是相当罕见,人们真正做的改变只有执行;只要你需要添加新的方法,比方说,你需要改头无论如何。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top