36

有人可以给我一个公共和私人标题如何工作的例子吗?我在网上做了一些阅读,但我似乎无法通过示例代码找到很多有用的信息。有人建议我应该使用私有标头来分隔代码的公共和私有部分以创建静态库。经过一番阅读,我对它的工作原理有了一个大致的了解,但我真的很感激有一个很好的例子来帮助我入门。具体来说,我不太明白的是如何将接口函数放在我的公共头文件中,而将私有变量/函数放在我的私有头文件中?谢谢!

编辑:

也许我的问题措辞不正确,但我的意思是,例如,我有 myMath.h 和 myMath.cpp,而 myMath.h 有:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();

private:
    double a;
    double b;
};

myMath.cpp 具有函数的实现。我怎样才能使myMath.h只有三个公共函数,而私有变量在另一个文件(例如myMath_i.h)中定义,这三个文件的方式是在我创建一个静态库后,用户只需要 myMath.h。这也意味着 myMath.h 不能#include myMath_i.h。所以像:

myMath.h:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();
}

和 myMath_i.h:

class myMath{
private:
    double a;
    double b;
}

当然这是不可能的,因为那时我将重新定义 myMath 类......

4

5 回答 5

28

您有两个头文件 MyClass.h 和 MyClass_p.h 以及一个源文件:MyClass.cpp。

让我们来看看它们里面有什么:

MyClass_p.h:

// Header Guard Here
class MyClassPrivate
{
public:
    int a;
    bool b;
    //more data members;
}

MyClass.h:

// Header Guard Here
class MyClassPrivate;
class MyClass
{
public:
    MyClass();
    ~MyClass();
    void method1();
    int method2();
private:
    MyClassPrivate* mData;
}

我的类.cpp:

#include "MyClass.h"
#include "MyClass_p.h"

MyClass::MyClass()
{
    mData = new MyClassPrivate();
}

MyClass::~MyClass()
{
    delete mData;
}

void MyClass::method1()
{
    //do stuff
}

int MyClass::method2()
{
    return stuff;
}

将您的数据保存在 MyClassPrivate 中并分发 MyClass.h。

于 2010-02-16T12:21:02.787 回答
12

您可以在单独的头文件(或一组文件)中声明要向库用户公开的所有接口和常量,并将其放入“inc”子目录中——这些头文件将是“public”的。您还将使用其他头文件来声明您不想公开的类和内容,因为它们是实现细节——您将把这些文件放入“src”子目录中——这些文件将是“私有的”。

这样,用户将被提示他必须只包含公共标题 - 那些在“inc”中并且只有那些标题包含他真正需要的东西,而所有其他标题都是“私有的”并且出于他的兴趣除非他想阅读实施。

当您将库发布为二进制文件时——无论是静态库还是动态库——你只复制“inc”内容和编译结果——这些对用户来说已经足够了,这样他就看不到你的实现源了。

于 2010-02-16T12:13:02.963 回答
3

我实际上发现双标头单源方法很脆弱。如果您在更改“私有”标头后忘记更新“公共”标头,您的代码可能会编译,然后在运行时在其他地方出现段错误。这种情况发生在我身上好几次了,所以我更喜欢编写除非一切都正确否则无法编译的代码。

MyClass.cpp 是这样实现的:

#define MYCLASS_IMPL
#include "MyClass.h"

// Implementation follows
...

MyClass.h 是有趣的一点:

#ifdef MYCLASS_IMPL
#include everything needed for the private: section
#endif

#include everything needed for the public: section only

class MyClass
{
public:
    // Everything that's public

#ifdef MYCLASS_IMPL
private:

    // Implementation details

#endif
};

如果目标是隐藏实现细节(例如封闭库),您可能需要采用双头方法。如果您不想仅仅为了使用一个类而拖入依赖项,那么单头方法可能是一个简单而强大的解决方案。


为了解决 Arton 的问题:我已经有一段时间没有看过这个了,但我认为这个问题与基于公共标头实例化对象有关,然后假设私有标头具有不同的对象大小。在运行时,对象的偏移量不匹配,导致内存崩溃。似乎 erenlender 的回答涵盖了这种情况,其中包含公共/私有类对。

于 2012-10-13T00:50:28.930 回答
2

公共标头是图书馆用户需要的标头。私有头文件是编译库所需的,但库用户不需要。执行拆分可能非常棘手,许多库根本不打扰。

于 2010-02-16T12:19:11.627 回答
0

我想知道同样的事情,因为我正在从 C 切换到 C++ 作为我的主要编程语言。我想最好的方法是使用接口(C++ 中的抽象类):您发布一个公共接口,而您的私有实现只是将该接口用作基类。

于 2012-06-22T13:07:13.703 回答