Removing pimpl from header file - c++

I have currently implemented a library using the pImpl idiom as such (just an example);
// library.h
class lib_public_type
{
class impl;
std::unique_ptr<impl> impl__;
public:
void libTypeFunction();
}
// library.cpp
#include "library.h"
class lib_public_type::impl
{
private:
std::string libVar1;
void libPrivateFunction1()
{
...
}
void libPrivateFunction2()
{
...
}
}
lib_public_type::libTypeFunction()
{
libPrivateFunction1();
libPrivateFunction2();
}
Now I would like to remove as much unneeded information from the header file as possible for another project using a built version of the library. I was wondering if there is a better way of removing the internals from the header of lib_public_type without resorting to maintaining two separate headers?
Would it be possible to do something like;
// library.h
#ifndef PROVIDES_IMPL
// define as empty string if not already defined
#define PROVIDES_IMPL
#endif
class lib_public_type
{
PROVIDES_IMPL
public:
void libTypeFunction();
}
// library.cpp
#define PROVIDES_IMPL class impl;\
std::unique_ptr<impl> impl__;
#include "library.h"
...
Or would this have unwanted consequences for the project using the library?

Related

Private variable declaration in implementation file

Consider this header file:
#ifndef __FOLDER_H__
#define __FOLDER_H__
#include <boost/filesystem.hpp>
class Folder
{
public:
Folder(char* arg);
private:
std::vector<boost::filesystem::path> files;
};
#endif
Everybody including Folder.h will also include boost/filesystem.hpp. However, there are no boost/filesystem types in the public interface of Folder. boost/filesystem.hpp kind of leaks out of Folder.h for the technical reason of declaring a private variable.
I would like to avoid this. Would it be best to declare private variables in the implementation file Folder.cc? Is there some syntax to declare a block of private variables in the implementation file?
There are quite a few idioms to hide the implementation details of a given class. Two of the ones I tend to use are PIMPL and interfaces.
PIMPL
PIMPL is a paradigm where you define a private structure with no definition in the header file, and all of your private implementation details are stored in this private structure. You then reference that structure with a pointer to the implementation, traditionally called pImpl (hence the name).
With the PIMPL idiom, Folder.h becomes this:
//this replaces the include guards and is available in almost all modern compilers.
#pragma once
class Folder
{
public:
Folder(char* arg);
private:
struct FolderImpl* pImpl;
};
And in Folder.cc, you can define FolderImpl as follows:
#include <vector>
#include <boost/filesystem.hpp>
struct FolderImpl
{
std::vector<boost::filesystem::path> files;
}
From there, any operations that work with the files member reference it by pImpl->files.
Interfaces
Interfaces are actually something I "stole" from Microsoft COM. The basic idea is you declare an abstract class, one without any member variables, and inherit from this class in a private header file compiled into your library.
In the Interface idiom, Folder.h becomes this:
class Folder
{
public:
virtual bool DoesFileExist(char* file) = 0;
virtual File* OpenFile(char* file) = 0;
...
static Folder* Create(char* arg);
};
Folder.cc looks like this:
#include "Folder.h"
#include "FolderImpl.h"
Folder* Folder::Create(char* arg)
{
return new FolderImpl(arg);
}
And FolderImpl.h is:
#include "Folder.h"
#include <vector>
#include <boost/filesystem.hpp>
class FolderImpl : public Folder
{
public:
FolderImpl(char* arg);
bool DoesFileExist(char* file) override;
File* OpenFile(char* file) override;
...
private:
std::vector<boost::filesystem::path> files;
};
At the cost of one level of indirection, you could consider doing something like this:
#ifndef FOLDER_H
#define FOLDER_H
#include <memory>
struct FolderPrivateVars;
class Folder
{
public:
Folder(char* arg);
private:
std::unique_ptr <FolderPrivateVars> private_vars;
};
#endif
And then in folder.cc
#include <boost/filesystem.hpp>
struct FolderPrivateVars
{
std::vector<boost::filesystem::path> files;
};
Folder::Folder(char* arg) : private_vars (std::make_unique <FolderPrivateVars> ())
{
...
}
Note that this approach hides all of Folders private variables from prying eyes, which would (for example) mean that modules using it would not need to be recompiled if these change. It might, however, have implications if you want to inherit from Folder.

Library design: Hiding dependencies

I'm attempting to build a library that uses a third-party library internally, but I do not want to expose and of this third-party library to the user of my library. This way, when the static library is built, the user will only need my header and the compiled library.
How do I deal with private members in my class definitions that are defined in the 3rd party library?
For example . .
header:
#include "ThirdPartyLib.h"
class DummyClass
{
TypeFromThirdParty tftp;
public:
bool checkStuff(const float) const;
};
implementation:
#include "ThirdPartyLib.h"
#include "dummy.h"
bool DummyClass::checkStuff(const float t)
{
return tftp.isOk(t);
}
The offending portion is the #include "ThirdPartyLib.h" in the header, as then the user of my library will need more than my library.
One way of getting around this might be to forward declare all third party types used in the header and then replace the value types with references, but I'm wondering if there is another method or design that I am completely overlooking?
The "private implementation class" or "pimpl" idiom is one approach. This keeps all mention of the third-party library (and other implementation details) out of the header, at the cost of an extra level of indirection:
// header
#include <memory>
class DummyClass {
public:
DummyClass();
~DummyClass();
bool checkStuff(float t);
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
// source
#include "DummyClass.h"
#include "ThirdPartyLib.h"
struct DummyClass::Impl {
TypeFromThirdParty tftp;
};
DummyClass::DummyClass() : impl(new Impl) {}
// This must be defined here, since ~unique_ptr requires Impl to be complete
DummyClass::~DummyClass() {}
bool DummyClass::checkStuff(float t) {return impl->tftp.isOk(t);}
Another approach is to define an abstract interface, and a factory to create the concrete implementation class. Again, this removes all implementation details from the header, at the cost of an extra indirection:
// header
#include <memory>
struct DummyInterface {
virtual ~DummyInterface() {}
virtual bool checkStuff(float t) = 0;
static std::unique_ptr<DummyInterface> create();
};
// source
#include "DummyClass.h"
#include "ThirdPartyLib.h"
struct DummyClass : DummyInterface {
TypeFromThirdParty tftp;
bool checkStuff(float t) {return tftp.isOk(t);}
};
std::unique_ptr<DummyInterface> DummyInterface::create() {
return std::unique_ptr<DummyInterface>(new DummyClass);
}

How to avoid #include dependency to external library

If I'm creating a static library with a header file such as this:
// Myfile.h
#include "SomeHeaderFile.h" // External library
Class MyClass
{
// My code
};
Within my own project I can tell the compiler (in my case, Visual Studio) where to look for SomeHeaderFile.h. However, I don't want my users to be concerned with this - they should be able to include my header without having to inform their compiler about the location of SomeHeaderFile.h.
How is this type of situation normally handled?
This is a classic "compilation firewall" scenario. There are two simple solutions to do:
Forward-declare any classes or functions that you need from the external library. And then include the external library's header file only within your cpp file (when you actually need to use the classes or functions that you forward-declared in your header).
Use the PImpl idiom (or Cheshire Cat) where you forward-declare an "implementation" class that you declare and define only privately (in the cpp file). You use that private class to put all the external-library-dependent code to avoid having any traces of it in your public class (the one declared in your header file).
Here is an example using the first option:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class some_external_class; // forward-declare external dependency.
class my_class {
public:
// ...
void someFunction(some_external_class& aRef); // declare members using the forward-declared incomplete type.
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
void my_class::someFunction(some_external_class& aRef) {
// here, you can use all that you want from some_external_class.
};
Here is an example of option 2:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class my_class_impl; // forward-declare private "implementation" class.
class my_class {
private:
std::unique_ptr<my_class_impl> pimpl; // a vanishing facade...
public:
// ...
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
class my_class_impl {
private:
some_external_class obj;
// ...
public:
// some functions ...
};
my_class::my_class() : pimpl(new my_class_impl()) { };
Say the external header file contains the following:
external.h
class foo
{
public:
foo();
};
And in your library you use foo:
myheader.h:
#include "external.h"
class bar
{
...
private:
foo* _x;
};
To get your code to compile, all you have to do is to forward declare the foo class (after that you can remove the include):
class foo;
class bar
{
...
private:
foo* _x;
};
You would then have to include external.h in your source file.

C++ - Nested include - Avoiding 'include nested too deeply error'

What is the best way of declaring my header files if I want to have the following connections in my C++ code, just so that I don't get the 'include nested too deeply error'?
On my edge class, I have some functions that need to return a Node object. Same for the Edge class, I have functions that need to return a Node object. However the compiler disallow me to have this nested loop thing.
Node.h
#ifndef _NODE_h__
#define __NODE_h__
#include "Edge.h"
public:
Node();
~Node();
void setName(string);
string getName();
void addEdge(Edge*);
vector<Edge* > getEdges() { return _edges; };
};
#endif
Edge.h
#ifndef _EDGE_h__
#define __EDGE_h__
#include "Node.h"
class Edge
{
public:
Edge();
Edge(bool);
~Edge();
bool hasBeenSeen() { return _seen; };
void reset() { _seen = false; }; // resets seen param to false
Node* getSource() { return _source; };
Node* getTarget() { return _target; };
void setSource(Node* source) { _source = source; };
void setTarget(Node* target) { _target = target; };
};
#endif
As others have suggested, use header guards. But also try forward declaring the classes in question. You may also have to work with pointers (rather than values) in at least one of your classes, but without seeing the code, we can't tell.
So edge.h should like something like:
#ifndef EDGE_H
#define EDGE_H
class Node; // forward declaration
Node functionB();
#endif
Note that you will have to define your function in a separate C++ file which then #includes "node.h".
If all this seems very complicated, then you should try simplifying your design. It is probably not necessary for nodes and edges to know about each other — a one way dependency should suffice.
And lastly, names containing double-underscores are reserved in C++ — you are not allowed to create such names in your own code.
Edge.h
#ifndef EDGE_H_INCLUDED
#define EDGE_H_INCLUDED
class Node;
class Edge
{
int edge_num;
public:
Edge(int i) : edge_num(i) { };
Node memberB();
};
#include "Node.h"
Node Edge::memberB() { Node n(edge_num); return n; }
Node functionB() { Node n(2); return n; }
#endif /* EDGE_H_INCLUDED */
Node.h
#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
class Edge;
class Node
{
int node_num;
public:
Node(int i) : node_num(i) { };
Edge memberA();
};
#include "Edge.h"
Edge Node::memberA() { Edge e(node_num); return e; }
Edge functionA() { Edge e(1); return e; }
#endif /* NODE_H_INCLUDED */
Note that I have forward declared the classes 'Edge' and 'Node' before the other header is included, so that by the time the function or member function is defined, the class it returns is also defined.
The problem with your include guards is that they don't match!
You test for _SOMETHING (one underscore) and then if not found you define __SOMETHING (two underscores); these two should match else the include guard does not work!
As others have noted avoid starting things with underscores as those are reserved for libs and OS.
This is prevented by using either pragma guards or #pragma once (the latter if your compiler supports it).
To use pragma guards, simply do this:
#ifndef SOME_IDENTIFIER
#define SOME_IDENTIFIER
// ... code ...
#endif
Make sure to change SOME_IDENTIFIER for every header file. Usually people make it NAME_OF_HEADER_H; make sure you change both instances of the identifier if you change one.
Also if you do this, make sure any #includes you do are inside the pragma guards.
If you just want to use #pragma once and your compiler supports it, you just have to add
#pragma once
to the top of your header file.
On another note, consider moving the definition of the functions functionA and functionB to their own .cpp files and keeping just the prototype in the .h files, so you don't get linker errors.

Inclusion problem

I have an inclusion pattern as follows:
/*
* Class1.h
*/
#ifndef CLASS1_H_
#define CLASS1_H_
#include "Class2.h"
namespace Class1_namespace
{
class Class1
{
Class2* Class2_ptr;
void Class1_member()
{
(*Class2_ptr).Class2_method();
}
};
}
#endif /* CLASS1_H_ */
/*
* Class2.h
*/
#ifndef CLASS2_H_
#define CLASS2_H_
#include "Class1.h"
class Class2
{
Class1_namespace::Class1 Class2_data;
public:
void Class2_method(){};
};
#endif /* CLASS2_H_ */
/*
* main.cpp
*/
#include "Class1.h"
int main()
{
return 0;
}
However, this leads to the error “'Class1_namespace' does not name a type.”
Is this error caused by the ordering of my inclusions?
What are some possible solutions? I'm dubious about forward declarations solving my problem.
Class1 doesn't need to include Class2.
When you have mutual dependency (which you don't -- you could just not include 2 in 1), you can usually solve it by using forward declarations instead of inclusions.
For example, let's say that Class1 looked like this
#include "Class2.h"
namespace Class1_namespace
{
class Class1
{
Class2* class2;
};
}
Where you think you need the include, you could instead do this:
class Class2;
namespace Class1_namespace
{
class Class1
{
Class2* class2;
};
}
to break the mutual inclusion.
In class1.h, try removing the unnecessary and circular #include of class2.h. If a circular dependency is required -- or even if not -- consider using forward declarations.