(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.
Related
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));
There is probably a really easy fix for this but it's boggling me currently. So, I'm writing C++ classes to the effect of:
Header.h:
#pragma once
//...
class arrayObj
{
private:
// some variables...
public:
//constructor, destructor, getters, etc...
friend void objManager::foo();
};
//...
class objManager
{
private:
//...
std::vector<std::shared_ptr<arrayObj>> array;
public:
void foo();
//other methods...
};
Now, as-is, my compiler will not find the class declaration of objManager (or the member function) declared for the friend inclusion. However, with the objManager declaration placed prior to the arrayObj, the arrayObj is no longer declared for the internal vector of shared pointers. Is there any way to forward declare objManager in this instance or otherwise solve this issue without dismantling the objManager into separate classes?
You need to forward-declare arrayObj, then put the full definition of the objManager, and then finally the definition of arrayObj:
class arrayObj;
class objManager {
std::vector<std::shared_ptr<arrayObj>> array; // OK, fwd-declare is fine for this
public:
void foo();
// etc.
};
class arrayObj {
public:
friend void objManager::foo();
// etc.
};
In order to declare a friend, that method has to already have been seen, so it has to go first. The forward declaration is a consequence of the vector.
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).
If I have a nested class like so:
class MyClass
{
class NestedClass
{
public:
// nested class members AND definitions here
};
// main class members here
};
Currently, the definitions of MyClass are in the CPP file but the definitions for NestedClass are in the header file, that is, I cannot declare the functions/constructors in the CPP file.
So my question is, how do I define the functions of NestedClass in the cpp file? If I cannot, what is the reason (and if this is the case, I have a vague idea of why this happens but I would like a good explanation)? What about structures?
You can. If your inner class has a method like:
class MyClass {
class NestedClass
{
public:
void someMethod();
};
// main class members here
};
...then you can define it in the .cpp file like so:
void MyClass::NestedClass::someMethod() {
// blah
}
Structures are almost the same thing as classes in C++ — just defaulting to 'public' for their access. They are treated in all other respects just like classes.
You can (as noted in comments) just declare an inner class, e.g.:
class MyClass {
class NestedClass;
// blah
};
..and then define it in the implementation file:
class MyClass::NestedClass {
// etc.
};
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();
};