Question

Is it somehow possible, to accomplish the following:

x.hpp - this file is included by many other classes

class x_impl; //forward declare
class x {
    public:
        //methods...
    private:
        x_impl* impl_;
};

x.cpp - the implementation

#include <conrete_x>
typedef concrete_x x_impl;    //obviously this doesn't work
//implementation of methods...

So basically, I want the users to include the file x.hpp, but be unaware of the conrete_x.hpp header.

Since I can use concrete_x only by a pointer and it appears only as a private data member, a forward declaration should be enough for the compiler to know how much space to prepare for it. It looks quite like the well-known "pimpl idiom".

Can you help me with this?

PS. I don't want to use a void* and cast it around..

Was it helpful?

Solution

Actually, it's even possible to completely hide from the user:

// Foo.hpp
class Foo {
public:

    //...

private:
    struct Impl;
    Impl* _impl;
};

// Foo.cpp
struct Foo::Impl {
    // stuff
};

I would just like to remind you that:

  • you will need to write a proper destructor
  • and thus you will also need a proper copy constructor, copy assignment operator, move constructor and move assignment operator

There are ways to automate PIMPL, at the cost of some black magic (similar to what std::shared_ptr does).

OTHER TIPS

As an alternative to the answer from @Angew, if the name concrete_x should not be made known to users of class x, you could do this:

in x.hpp

class x_impl;
class x {
  public:
    x();
    ~x();
    //methods...
  private:
    x_impl* impl_;
};

in x.cpp

#include <concrete_x>
class x_impl : public concrete_x { };

x:x() : impl_(new x_impl) {}
x:~x() { delete impl_; }

This will only work when the forward declaration declares the actual name of the class. So either change x.hpp to:

class concrete_x;
class x {
    public:
        //methods...
    private:
        concrete_x* impl_;
};

or use the name x_impl for the class defined in the header <concrete_x>.

That's what interfaces are for. Define an interface (pure virtual class) in your shared header file and give it to users. Inherit your concrete class from the interface and put it in the non-shared header file. Implement the concrete class in the cpp file (you can even define the concrete class inside the cpp).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top