I have a class which I want to create an interface for without showing any of the implementation (not because it's closed source, but because of a lot of unnecessary headers such as OpenGL coming with it), let's call that class Foo. I know this is commonly done through either the PImpl-idiom or virtual interfaces, and I've implemented the PImpl-idiom for that class.
However, this class has public functions which returns other classes that are also including those headers, so obviously I can't return those objects as-is as that'd require me to include headers I don't want to include in Foo.h. However, these classes are used internally within the library a lot, and thus I don't want to implement them with PImpl as that'd introduce a lot of overhead (they're used a lot within a 3D renderer's code). Let's call one of them Bar:
Foo.h:
#include "Bar.h"
class Foo
{
private:
class impl;
std::unique_ptr<impl> m_pimpl;
public:
Foo();
Bar& get_bar();
};
Foo.cpp:
#include "Foo.h"
class Foo::impl {
private:
Bar m_bar;
public:
Bar& get_bar();
};
Foo::Foo() : m_pimpl{std::make_unique<impl>()}
{ }
Bar& Foo::get_bar() {
return m_pimpl->get_bar();
}
For this to work I need to #include "Bar.h", but Bar.h might include headers I want to hide. This leaves me with the option to make Bar use the PImpl-idiom as well, but I don't want that overhead for Bar because Bar is used a lot internally within Foo. However, I figured a way to solve this, but I'm not very sure about it as I haven't seen it used anywhere before:
Using PImpl without an owning pointer/reference to simply wrap a class and create a interface for it. This way the overhead only applies when outside of Foo, but internally it'll still use the non-wrapped class.
For example, let's say PBar is wrapping Bar:
PBar.h:
class Bar;
class PBar {
private:
Bar &m_bar;
public:
explicit PBar(Bar &bar);
void do_stuff();
};
PBar.cpp:
#include "PBar.h"
#include "../impl/Bar.h" // This is the actual Bar implementation
PBar::PBar(Bar &bar) : m_bar(bar) {
}
void PBar::do_stuff() {
m_bar.do_stuff();
}
And Foo instantiates PBar on creation with a reference to the actual Bar inside the object:
Foo.h
#include "PBar.h"
class Foo
{
private:
class impl;
std::unique_ptr<impl> m_pimpl;
PBar m_bar;
public:
Foo();
PBar& get_bar() { return m_bar; }
};
Foo.cpp:
class Foo::impl {
private:
Bar m_bar;
public:
Bar& get_bar();
};
Foo::Foo() : m_pimpl{std::make_unique<impl>()},
m_bar(impl->get_bar())
{ }
Is this pattern ever used? Are there any other ways I can solve this problem? It's more or less the same principle as PImpl, but is there anything bad about it I haven't yet thought about? It definitely feels even less clean, but I can't see how this could be done in any other way.
Also, I want neither PBar or Bar to be constructable outside of Foo, so that's not a problem.
Thanks!
You cannot (should not) change the object referenced by a reference member: how do you do here: Foo a,b; a=b; (supposing you initialize a non null unique_ptr). This is easily corrected replacing the reference by a pointer.
This look like a good idea, what you do is caching a dereferencement. But you are loosing some efficiency of the pimpl idiom and you are doubling the size of Foo.
Have you thought in making the class impl standard layout and putting Bar at a known offset inside impl:
Foo.h
constexpr auto impl_bar_offset = 8;
//...
class Foo{
private:
class impl;
std::unique_ptr<impl> m_impl;
public:
bar& get_bar(){
assert(m_impl);
return *reinterpret_cast<bar*>(
reinterpret_cast<unsigned char*>(m_impl.get())+impl_bar_offset);
}
};
Foo.cpp
class impl{
long a_long;
bar a_bar;
//...
};
static_assert(impl_bar_offset==offsetof(impl,a_bar));
Related
This question already has answers here:
Allowing a "friend" class to access only some private members
(9 answers)
Closed 5 years ago.
Suppose that I have these classes:
class Bar;
class Foo {
private:
// stuff here
public:
void methodForClassBar();
};
What I want to do is make methodForClassBar private in a way that class Bar still be able to call it. But I don't want class Bar to be able to access any other private members of Foo.
My current solution is this: put methodForClassBar into private, and create an accessor class (FooInterfaceToClassBar, this can only be accessed by Bar), which is a friend to Foo. So with this accessor class, I can call methodForClassBar:
class FooInterfaceToClassBar;
class Foo {
private:
// stuff here
private:
void methodForClassBar();
friend FooInterfaceToClassBar;
};
class FooInterfaceToClassBar {
private:
static void inline callMethod(Foo &foo) {
foo.methodForClassBar();
}
friend class Bar;
};
void Bar::someMethod(Foo &foo) {
FooInterfaceToClassBar::callMethod(foo);
}
Is there a other/better (more convenient) method to achieve this, without any runtime performance cost (I'd like to avoid adding interfaces with virtual methods)?
You can restrict the access to the interface's method to only Bar in this way:
class FooInterfaceToClassBar {
private:
FooInterfaceToClassBar() = delete; // avoid accidental instantiation
static void inline callMethod(Foo &foo) {
foo.methodForClassBar();
}
friend class Bar;
};
Although a little inconvenient, this approach gives the most precise control on the visibility, with the minimum of overhead. A variant could be to make the interface class a nested class of Foo. But the only advantage is not to clutter the namespace.
Other approaches
Another approach could be to use inheritance. However, single inheritance will not really do the trick : it can easily give more access to Bar's privacy than expected.
If methodForClassBar() doesn't need itself to access other private stuff, you could isolate it for the Bar access using multiple inheritance. This approach requires however heavy contraints and is not as flexible as yours:
class Foo0 {
//... // the real private stuff goes here
};
class Foo1 {
private:
void methodForClassBar();
friend Bar;
};
class Foo : public Foo0, public Foo1 {
//...
};
...
void Bar::someMethod(Foo &foo) {
foo.methodForClassBar();
}
Furthermore, if you can isolate the method so easily from the rest, you could as well do the same things directly within the Bar method, which makes this alternative look a little bit clumsy.
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..
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).
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).
(In C++) I have a class whose structure is declared in a header file. That header file is included in lots of source files, such that when I edit it I need to recompile lots of files.
The class has a set of private functions which are only called in one source file. Currently they are declared in the class structure in the header file. When I add a new function of this type, or edit the arguments, it therefore causes recompilation of lots of files. I would like to declare the functions somewhere else, such that only the file that defines and calls them is recompiled (to save time). They still need to be able to access the internal class variables, though.
How can I achieve this?
Use the pImpl idiom - Your visible class keeps a pointer to the real class and forwards calls to public member functions.
EDIT: In response to comments
// Foo.h:
class FooImpl; // Do *not* include FooImpl.h
class Foo {
public:
Foo();
~Foo();
//.. also need copy ctor and op=
int bar();
private:
FooImpl * Impl;
};
// FooImpl.h:
class FooImpl {
public:
int bar() { return Bar; }
private:
int Bar;
};
// Foo.cpp:
#include "FooImpl.h"
Foo::Foo() { Impl = new FooImpl(); }
Foo::~Foo() { delete Impl; }
int Foo::bar() { return Impl->bar(); }
Keep the actual implementation of your class in FooImpl - Foo should have copies of the public members of FooImpl and simply forward calls to these. All users will include only "Foo.h" - you can change all the private details of FooImpl without the users of Foo seeing any changes.
There is no way to declare member functions of a class outside the main class declaration. So, if you want to declare, outside of the class in question, functions that can access member variables of a particular instance of the class, then I see no alternative but to pass that instance to the function. Furthermore, if you want the functions to be able to access the private and protected variables you will need to put them in a new class and make the original class a friend of that. E.g.
header.h:
class FooImpl;
class Foo {
public:
int bar();
friend class FooImpl;
private:
int var;
}
impl.cpp:
#include "header.h"
class FooImpl {
public:
int bar(Foo &);
}
int FooImpl::bar(Foo &foo) {
return foo.var;
}
int Foo::bar() {
return FooImpl::bar(*this);
}
Are you looking for Compiler Firewall, a.k.a. PIMPL?
Create an abstract base class which contains only the public functions and reference this in your headers. Create your real class as an implementation somewhere else. Only source files which need to create your class need to see the implementation class header.
This is a very noobish mistake, but I dont know whats happening here.
There are loads of pimpl examples but I dont understand why this isn't working (this was one of the examples more or less but I dont see the difference).
I have a very simple Pimpl example, but it wont work.
// Foo.hpp
#include <boost/scoped_ptr.hpp>
class Foo
{
struct Bar;
//boost::scoped_ptr<Bar> pImpl;
Bar* pImpl;
public:
Foo();
~Foo() {}
int returnValue();
private:
};
and
// Foo.cpp
#include "foo.hpp"
struct Foo::Bar
{
Bar() {}
~Bar() {}
int value;
};
Foo::Foo() : pImpl(new Bar())
{
pImpl->value = 7;
}
int Foo::returnValue() {
return *pImpl->value;
}
Compiling this gives me the error.
C2100: illegal indirection.
Thanks.
int returnValue() should be a member function:
// vvvvv
int Foo::returnValue() {
return pImpl->value; // no need to dereference, value isn't a pointer
}
You need to define your constructor, copy-constructor, copy assignment operator, and destructor after the implementation class has been defined. (Otherwise the implicit destructor is dangerous, and scoped_ptr won't let you do that):
// Foo.hpp
#include <boost/scoped_ptr.hpp>
class Foo
{
struct Bar;
boost::scoped_ptr<Bar> pImpl;
public:
Foo();
~Foo();
int returnValue(); // could be const (so should be)
private:
// just disable copying, like scoped_ptr
Foo(const Foo&); // not defined
Foo& operator=(const Foo&); // not defined
};
And:
// Foo.cpp
#include "foo.hpp"
struct Foo::Bar
{
int value;
};
Foo::Foo() :
pImpl(new Bar())
{
pImpl->value = 7;
}
Foo::~Foo()
{
// okay, Bar defined at this point; scoped_ptr can work
}
int Foo::returnValue()
{
return pImpl->value;
}
As an aside, you may have a problem using boost::scoped_ptr for a pImpl because your pImpl is forwardly declared and you may find that the class needs to be fully visible in order to call scoped_ptr's destructor (which deletes the underlying).
Some compilers will allow you to work around this by putting the body of your destructor in the compilation unit (the .cpp file) where the class is visible.
The simplest solution is that if your destructor has to be implemented anyway you may as well just use a raw pointer and have your destructor delete it. And if you want to use something from boost to help you, derive your outer class from boost::noncopyable. Otherwise ensure you handle copy-construction and assignment properly.
You can use shared_ptr to your pImpl. You can then copy your outer class around happily although they share the same underlying unless you overload the copy-constructor and assignment operator to do otherwise.
I want to hide an implementation in implementation file. If the object is not public, I don't want the object's header to leak everywhere my class is used.
Suppose I have header file A.h for my class A:
#include "Foo.h"
class A{
private:
Foo foo;
public:
do_stuff();
};
Now wherever I would include A.h, Foo.h also would be included. But I have no use for class Foo anywhere outside of class A. I would rather not have this #include "Foo.h" line. Is there any way to move the declaration of 'foo' variable inside the implementation A.cpp?
I suspect one possible solution involves adding a layer of abstract class (interface analogy). Is it the best solution?
Thank you.
Use a pointer to Foo and allocate it dynamically, rather than using a member object. Then you only need to include Foo.h in A.cpp.
class Foo;
class A{
private:
Foo* foo;
public:
do_stuff();
}
David's got the right answer. I'll refer to this article for a little more treatment on this kind of "opaque pointer" trick, as you can get more elaborate with it, depending on your needs:
http://en.wikipedia.org/wiki/Opaque_pointer
Also, it's a good idea to use shared_ptr types for this purpose instead of raw pointers like the sample. This will take care of cleaning up resources for you automatically, once the last reference to Foo goes out of scope.
Yes. Choose yer poison!
Option 1. Forward declaration in interface.
class A {
private:
class Foo;
Foo* foo;
};
Option 2. ABC.
// A.hpp
class A {
public: virtual void do_stuff() = 0;
};
// A.cpp
class A_impl : public A {
class Foo { /*etc*/ };
Foo foo;
void do_stuff (){...}
};
Option 3. Private is private. It's "hidden" as far as the public API goes, which is all that matters:
class A {
private:
class Foo {
...
};
private_::Foo foo;
public:
do_stuff();
};
Option 4. Just put the declaration in a "non-public" namespace.i.e., omit it from documentation and name it something to frighten away prying eyes:
namespace private_ {
class Foo {
...
};
}
class A {
private:
private_::Foo foo;
public:
do_stuff();
};