隐藏c ++库的私有成员

时间:2013-07-09 17:27:08

标签: c++ shared-libraries static-libraries

我编写了一个库(无关紧要),它显然有自己的头文件。现在,我想隐藏该头文件的私有元素,所以如果我向某人提供我的库,他/她应该只看到公共成员(最好没有类定义,除了函数定义之外)。一种方法是创建C风格的头文件,它将包含某种“init”方法,该方法将用于创建实际类库的实例,并且用户必须将该对象的指针传递给每个函数做好这份工作。

这是一个好习惯吗?

还有其他公开接受的做法吗?

提前致谢。

6 个答案:

答案 0 :(得分:11)

除了工厂模式(在我看来,它可能变得笨拙)之外,您还可以隐藏PIMPL背后的私有成员(指向IMPLementation的指针):

// Interface.hpp
class Implementation;
class Interface {
public:
    Interface() : pimpl(new Implementation()) {}
    void publicMethod();
private:
    std::unique_ptr<Implementation> pimpl;
};

// Interface.cpp
class Implementation {
public:
    void PrivateMember();
};

void Interface::publicMethod() { pimpl->PrivateMember(); }

这具有以单指针间接为代价隐藏实现的优点,与典型的基于继承的Factory模式没有太大区别。

这也可以是ABI稳定的。对实现的更改不会影响链接,因为程序的其余部分不会显示任何更改。例如,这是在实现共享对象时使用的好模式。

这也是一种常见的C ++习惯用法,因此其他C ++程序员会毫无疑问地认出它。

对于将遵循Singleton模式的类,您可以完全避免暴露PIMPL,只需将整个实现写入namespace文件中的匿名.cpp即可。可以根据需要添加任意数量的状态和私有函数,甚至不需要在界面中暗示它。

答案 1 :(得分:6)

您可以创建一个公开可见的界面。使用您想要公开的函数创建一个抽象类,然后让您的实现扩展它。

例如,界面:

class Interface {
public:
    virtual void publicMethod() = 0;
...
};

实施:

class Implementation : Interface {
public:
    virtual void publicMethod();
private:
    int hiddenMethod();
};

然后您只导出Interface的符号。现在,为了让库的用户获得实际上是实现的接口实例,你需要提供一个工厂:

class Factory {
public:
    //can create and return an Implementation pointer, but caller will get an Interface pointer
    std::shared_ptr<Interface> getImplementationInstance();
}

答案 2 :(得分:2)

基于Eric Finn's answer,您可以声明一个interface类来保存所有被认为是您的API的公共方法,并隐藏继承{的实现类中的所有实现和私有成员/方法{1}}课程,以下是示例:

您的头文件:my_api.h

interface

您的实现(共享库):my_api.cpp(当您将其设为共享库时,用户不会看到此内容) 所以你可以在这里隐藏所有的实现和私有方法/成员

// your API in header file
// my_api.h
class interface {
public:
    static interface* CreateInstance();
    virtual void draw() = 0;
    virtual void set(int) = 0;
};

用户如何使用您的API:

#include "my_api.h"
        // implementation -> in .cc file
class implementation : public interface {
    int private_int_;
    void ReportValue_();
public:
    implementation();
    void draw();
    void set(int new_int);
};

implementation::implementation() {
    // your actual constructor goes here
}

void implementation::draw() {
    cout << "Implementation class draws something" << endl;
    ReportValue_();
}

void implementation::ReportValue_() {
    cout << "Private value is: " << private_int_ << endl;
}
void implementation::set(int new_int) {
    private_int_ = new_int;
}
interface* interface::CreateInstance() {
    return new implementation;
}

输出:

#include <iostream>
#include "my_api.h"

int main(int argc, const char * argv[])
{

    using namespace std;
    interface* a; interface* b;
    a = interface::CreateInstance();
    a->set(1);
    b = interface::CreateInstance();
    b->set(2);
    b->draw();
    a->draw();
    return 0;
}

在这种模式中,你的api只是一个像工厂一样工作的抽象类,你也可以在不同的类中实现虚方法,并指定你想要调用的实例。

答案 3 :(得分:1)

我认为你需要创建动态链接库(dll)。

Please take a quick look at this link:

答案 4 :(得分:0)

您可能需要查看信封/字母惯用语,网桥设计模式或代理模式。基本上,您将创建一个外部(公共)类,它只是将您的公共方法调用转发给内部(私有)类。您的InnerClass.h标头只需要在OuterClass.cpp和InnerClass.cpp源文件中可见/已知。

这些模式中的每一个都提供了一种将实现与接口分离的机制,以便调用者不会耦合到实现。有时希望减少编译器对大型C ++项目的依赖性。想要这样做的另一个常见原因就是当你想隐藏实现细节时,调用者只能看到一个不透明的指针。

=======  OuterClass.h =====
class InnerClass; // forward declaration is all that's needed

class OuterClass {
    private:
        InnerClass *pInner;

    public:
        InnerClass();

        bool doSomething();
};

======= OuterClass.cpp ======
#include "OuterClass.h"
#include "InnerClass.h"

OuterClass::OuterClass() : 
    pInner(new InnerClass())
{
}

bool OuterClass::doSomething()
{
    return pInner->doSomething();
}

答案 5 :(得分:0)

实际上,有一种方法可以不必使用类。我遇到了同样的问题,这是一个非常简单的解决方案:

只需将您的私人物品放入.cpp文件中。您的头文件将如下所示:

// These will be visible to everyone using this library
void function();
int someNumber = 2;

和您的.cpp文件:

void function() {
    // whatever this function does
}
// This will be only visible to the library itself
static void secretFunction() {
    doSomeSecretStuff;
}

static int PIN = 1234;
// Okay, if you write this Number into your library and expect it to be safe,
// then screw you, but at least no one will be able to access it with code

从外部调用“ public”函数时,您现在不再需要该类的任何实例:只需将库放置在正确的目录中并包含它,但您可能已经做好了处理),然后调用Lib.h文件中的函数名称。在本例中,它看起来像这样:

#include "Lib.h"

int main(int argc, const char * argv[]) {
    function();
    return 0;
}

感谢Edgar Bonet帮助我在Arduino Stackexchange上找到了该解决方案!