C++ 类库和pimpl-拆分类可访问性

C++ 类库和pimpl-拆分类可访问性,c++,pimpl-idiom,C++,Pimpl Idiom,我想使用pimpl习惯用法创建一个类库,这样就可以为库的用户隐藏我的实现细节 有没有可能创建一个类,其中一些方法是公共的,可以从用户的角度调用,而这些方法只能从内部调用 现在我只看到一个带有friend关键字并将内部方法声明为private的解决方案 例如: MyPartiallyVisibleClass:包含用户可以访问的方法和只对库内部可访问的方法的混合类。 InternalClass:在库中内部初始化。用户永远不会知道这个激进分子 // MyPartiallyVisibleClass.h:

我想使用pimpl习惯用法创建一个类库,这样就可以为库的用户隐藏我的实现细节

有没有可能创建一个类,其中一些方法是公共的,可以从用户的角度调用,而这些方法只能从内部调用

现在我只看到一个带有friend关键字并将内部方法声明为private的解决方案

例如: MyPartiallyVisibleClass:包含用户可以访问的方法和只对库内部可访问的方法的混合类。 InternalClass:在库中内部初始化。用户永远不会知道这个激进分子

// MyPartiallyVisibleClass.h: Will be included by the user.
class MyPartiallyVisibleClass
{
private:
    class Impl;          // Forward declare the implementation
    Impl* pimpl;

    InternalMethod();    // Can only be called from within the library-internals.

public:
    UserMethod();       // Will be visible and callable from users perspective.
}

// MyPartiallyVisibleClass.cpp
class MyPartiallyVisibleClass::Impl
{
private:
    InternalMethod();

public:
    UserMethod();

    friend class InternalClass;
}

// Internal class that will not be included into users application.
class InternalClass
{
public:
    InternalMethod()
    {
        MyPartiallyVisibleClass pvc;
        pvc.InternalMethod();
    }
}

有更好的方法吗?

有优点也有缺点

从源代码的角度来看,如果只分发头文件和二进制文件,那么源用户将看不到cpp文件中的所有内容

因此,
MyPartiallyVisibleClass::Impl::Usermethod
也不可见,但它是公共的,可以在声明的cpp文件中的任何地方调用

如果您不想在内部重复外部方法,则外部类和内部类之间可能需要零向、单向或双向友谊。它看起来像是封装中断,但事实并非如此,因为这里的“胶囊”是外部类。如果一切都在你的责任范围内,那么创建复杂的内部隐私层次结构(公共-外部、私人-外部、公共-内部-私人-内部-公共甚至更内部…等等)可能会变得毫无意义。除非内部部分太大,无法分配给不同的开发人员,因此需要另一个级别的接口和实现

然而,从二进制用户的角度来看,每一个没有内联的函数都存在,并且(具有外部链接)它的名称可以在库中使用,因此它可以通过编写另一个头来“调用”,从而使它对其他源公开。我将只是一个未记录的功能

public/private等的概念是为了代码安全(避免您不希望承诺维护的函数始终保持相同的“契约”可用,从而使外部代码更稳定,消除不必要的依赖性),而不是为了“安全”(避免想调用的人找到调用的方法)

还有另一个缺点:模板不能隐藏在源代码中,因为它们必须扩展到用户的源代码空间(而不是开发人员二进制空间)。泛型编程、函数静态同态等的发展使得pimpl习语越来越没有吸引力


现在有许多程序是由单个cpp文件生成的,这些文件实例化了单个“管理器对象”,其整个功能都是由只包含头的库构成的。信不信由你,这种编程方式使代码在编译器之间更加可移植,因为对于每个可能的客户端编译器,它不必以不同的二进制形式存在。并且不一定会延长构建时间:对于不经常更改的代码,可以生成一次预编译头。谁在乎用户是否能看到代码?如果他想使用它并得到支持,那么不恰当地改变它并不是他的兴趣所在。如果他想黑客或偷窃,他无论如何会找到另一种方法。

你为什么需要这样做?最简单的方法是在用户类中只放置公共方法,并将所有血淋淋的细节留给实现。除非考虑每一个关于piml的问题,一个复制品……这里的每一个都被我认为的那个帖子所覆盖。这些话题一次又一次地被过度讨论。除了一般原则,我在这里看不到任何具体的东西。事实上,pimpl现在仍然相当普遍,所以“越来越不吸引人”可能会被其他人理解。它仍然很吸引人。事实上,尽管有这篇文章,我个人还是建议使用pimpl成语。更糟糕的可能是这1-2种方式的朋友。@LaszloPapp:那么标准库是最糟糕的,至少对你来说是这样。但别担心,这是一个古老的争论:看,不,我并没有说它最终是坏的。我说过,在这种情况下,这不是正确的选择,依我看