I want to avoid recompilation of everything that includes a public header file, just because something changed in the private part of a class definition. I'm investigating other options beside PIMPL.
This is what I tried:
I created a library that contains a class A:
A_p.h contains private part of class A
void PrivateMethod(int i);
A.h the public header file:
class A
{
public:
A();
virtual ~A();
// other public members
private:
#ifdef A_PRIVATE
#include "A_p.h"
#endif
};
A.cpp
#define A_PRIVATE
#include "A.h"
A::A() {}
A::~A() {}
void A::PrivateMethod(int i) { }
I then created an Win32 console project that includes the public header (A.h) and links against the .lib file.
Everything seems to work, but I'm wondering for any pitfalls along the way. Can anyone elaborate on this?
Abstract classes permit you to declare a public interface but have private data and functions, by subclassing the abstract class.
A key reason this will not work the way you describe, and therefore is not supported in the C++ standard, is that your proposed public declaration makes it impossible to know the size of A
. The public declaration does not reveal how much space is needed for the private data. Therefore, code that sees only the public declaration cannot perform new A
, cannot allocate space for a definition of array of A
, and cannot do arithmetic with pointers to A
.
There are other issues, which might be worked out in some way, such as where pointers to virtual function members are located. However, this causes needless complications.
To make an abstract class, you declare at least one virtual function in the class. A virtual function is defined with = 0
instead of a function body. This says it has no implementation, and therefore there can be no object of the abstract class except as a sub-object of a class derived from it.
Then, in separate, private code, you declare and define a class B
that is derived from A
. You will need to provide ways to create and destroy objects, likely with a public “new” function that returns a pointer to A
and works by calling a private function that can see the declaration of B
and a public “delete” function that takes a pointer to A
and works by calling a private function that can see the declaration of B
.