Private/public header example?

我们两清 提交于 2019-11-29 21:25:41

You have two header files MyClass.h and MyClass_p.h and one source file: MyClass.cpp.

Lets take a look at what's inside them:

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;
}

MyClass.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;
}

Keep your data in MyClassPrivate and distribute MyClass.h.

You can declare all the interfaces and constants you want to expose to the library user in a separate header file (or a set of files) and put it into "inc" subdirectory - those headers will be "public". You will also use other header files to declare classes and stuff you don't want to expose since theay are implementation details - you will put those files into "src" subdirectory - those will be "private".

This way the user will be given a hint that he has to include only the public headers - those that are in "inc" and only those headers contain the stuff he really needs, while all other headers are "private" and out of his interest area unless he wants to read into the implementation.

When you publish your library as binary - either static or dynamic library - you only copy the "inc" contents and the compilation result - those are enough for the user and this way he doesn't see your implementation sources.

I've actually found the two-header-one-source approach to be fragile. If you forget to update the 'public' header after changing the 'private' header, your code may compile, and then segfault somewhere else at run time. I've had this happen to me a few times, so I prefer to write code that won't compile unless everything is correct.

MyClass.cpp is implemented like this:

#define MYCLASS_IMPL
#include "MyClass.h"

// Implementation follows
...

MyClass.h is the interesting bit:

#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
};

If the goal is to hide implementation details (for e.g. a closed library), you may need to go with the two-header approach. If you don't want to drag in dependencies just to use a class, the single-header approach can be a simple and robust solution.


To address Arton's question: It's been a while since I've looked at this, but I think the issue had to do with instantiating objects based on the public header, then assuming a different object size with the private header. At run time, an offset into the object wouldn't match, causing a memory smash. It seems like erenlender's answer covers this case with a public/private class pair.

Public headers are those needed by the users of the library. Private headers are those needed to compile the library, but which are not needed by library users. Performing the split can be quite tricky, and a lot of libraries simply don't bother.

I was wondering the same thing since I'm switching from C to C++ as my main programming language. I guess the best way is to use interfaces (abstract classes in C++): you publish a public interface, and your private implementation just use the interface as base class.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!