Static library: hiding private members from header file - c++

I wish to compile part of my code as a static library to include in other project. Of course I'll have to distribute the compiled library and an header file containing the class declaration and the public members, but I don't know if it's possible to move all private members and declarations to a place different than the header file.
Example:
In the project.h file:
class MyClass
{
public:
MyClass();
void Give_me_an_input(int);
int Get_your_output();
private:
int a, b;
int MySecretAlgorithm();
};
In the .cpp file:
MyClass::MyClass()
{
a = 1;
b = 0;
}
void MyClass::Give_me_an_input(int c)
{
b = c;
}
int MyClass::Get_your_output()
{
return MySecretAlgorithm();
}
int MyClass::MySecretAlgorithm()
{
return (a + b);
}
Is there a way to move all private members int a, b; and int MySecretAlgorithm(); to a place different than the header file?

The pointer to implementation idiom can be used in such a scenario, commonly referred to as pimpl.
The basic idea is to take the implementation details out of the declaration
and simply have an opaque pointer to the implementation details.
std::unique_ptr is used in the the following example; but you could of course just use normal pointers.
// my_class declaration unit.
class my_class {
private:
class impl;
unique_ptr<impl> pimpl;
public:
};
// my_class implementation unit
class my_class::impl {
int whatever;
int whenever;
};
my_class::my_class(): pimpl( new impl )
{
}

Over the years I've seen some hacks to do this, but I don't think they are worth it. If your library is reasonably 'chunky' (ie: no method is being called a billion times a microsecond); and you can re-write chunks of your code...
You might consider making all the public stuff an abstract class (all virtual = 0) and then deriving your concrete classes from it.
Down sides of this:
- All your public calls become virtual (some optimizations can bypass this, but not often).
- You can't 'new up' your classes anymore, you'll need to implement a factory pattern.
The problem with any of the other hacks I'm familiar with is that they basically declare the methods in one set of headers, and then redeclare the same things with the 'real' implementation in private headers - depending on the linker to match up the names. A couple problems here are:
Maintaining this mess sucks. You can't use an #ifdef because it sounds like you want to physically hide your implementation. So you have dual maintaining, or a build step that generates your public headers.
Can only be used via pointer. You have to play games making constructors private and still have a factory because the compiler won't generate structs of the right size if you let the client gen it by value (or even with new).
Finally, I once saw a hack where the programmer tried to declare a byte array in the private area of the 'public' class so that the client code could still declare by value or 'new' it themselves. This suffers all the previous problems, plus you probably don't want to have to 'know' the size of the structs since they depend on packing and alignment. Your 'build step' would more or less have to have a runtime component that used sizeof() - and now you have a versioning problem if you want to change the size of the struct/class.

Related

Do C++ private functions really need to be in the header file?

I have always thought of header files as a sort of 'public interface' describing a class, in which case it would be better to keep private fields and functions in the .cpp file.
I understand that private fields need to be in the header so that other classes can tell how much memory an instance of a class will consume, but it occurred to me as I was about to write a private helper function, that this function could be made static, in which case there was no need for it to be 'part of the class' at all, it could just as easily be a regular function in the class definition's .cpp file.
It then occurred to me that all private functions could potentially be rewritten to be static by accepting pointers/references to class fields instead of expecting to be defined in the class.
This would eliminate the need to declare any private functions in the header file.
I do like to follow conventions, so is it considered an established convention in C++, that non-static private functions should be in the header file? What about static functions or static constants?
I'm going to put in some code to explain what I'm getting at:
.h file:
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass
{
private:
int x;
public:
void combineWithX(int y);
};
#endif
.cpp file
#include "SomeClass.h"
void someHelper(int* x)
{
*x = (*x) + 1;
}
void SomeClass::combineWithX(int y)
{
someHelper(&x);
x += y;
}
Note that someHelper(int* x) in the .cpp file references the private member x in spirit, but not directly, and therefore does not need to appear in the header. I'm wondering if this sort of thing is considered 'bad style'.
Private helper functions can be hidden from the public header file by moving them to an inner class. This works because the inner class is considered part of the class and can access the surrounding class's private members.
Unlike the PIMPL idiom, this does not have any dynamic allocation or indirection penalty. Compile times should be faster when editing/refactoring private functions, as there isn't any need to recompile all the files, including the public header.
Example:
public .h file
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass
{
private:
// Just forward declaring in public header.
struct Private;
int x;
public:
void combineWithX(int y);
};
#endif
in .cpp file
#include "SomeClass.h"
// Declare all private member functions of SomeClass here
struct SomeClass::Private
{
static void someHelper(SomeClass& self)
{
self.x = self.x + 1;
}
};
void SomeClass::combineWithX(int y)
{
Private::someHelper(*this);
x += y;
}
I agree that it is a problem that implementation details need to be exposed in a header file; it interferes with separation of interface and implementation.
Moving private helper functions to be free functions in the .cpp file (I presume that is what you meant by "static") won't work if those functions need to access private member variables.
You may be interested to look at the pImpl idiom (more)
Sometimes I see people using two different headers, a public header and a private one, like this:
// SomeClass.h - - - -
SomeClass
{
public:
// public functions
}
// SomeClass_.h - - - -
SomeClass
{
public:
// public functions
private:
// private functions
}
// SomeClass.cpp - - - -
#include "SomeClass_.h"
// SomeClass implementation
This has the advantage of a public header that isn't cluttered with private function declarations, but it requires the developer to maintain 3 copies of each function signature.
Header files have long been recognized by many as being problematic in general, not only because of the added maintenance overhead associated with them, but also because of the effect they have on the build environment. It's easy to write code or set build settings that cause a cascade of system or external headers to fail to compile, resulting in a large number of potentially obscure errors. C++20 Modules are an alternative that may be worth exploring.

what does one sacrifice with this pimpl alternative?

I have, unfortunately, used Qt a lot (it purports to be many things that it is not) and since Qt uses the pimpl idiom extensively, I've gotten a lot of experience with the pimpl pattern as well and learned I don't like it. One alternative I like to use is:
// .hpp file
struct A
{
private:
struct B;
int a{};
};
// .cpp file
struct A::B
{
// replaces a private member function
static void f(A& a)
{
++a.a;
}
};
But what is sacrificed using this approach instead of using private function members or pimpl? Performance, binary compatibility? With pimpl, we know that it is performance, because of 1 level of added indirection.
Well, for one - this won't work if struct B needs to be a class template that takes arbitrary type parameters.
If A::B only contains static methods/data, there is no point in exposing that at all in the header. You can much simpler only implement those function in the .cpp file, without making them part of to the class.
// .hpp file
struct A
{
};
// .cpp file
void f(A& a)
{
// some function
// Might be called from the implementation of methods of `A`
}
So there is not really a reason to have a nested class in the first place.
On the other hand, if you do have non-static data/... in A::B that needs to be associated with instances of A (the situation where the pimpl idiom is used), then you somehow need to associate a A::B instance with every instance of A.
A straight forward way to do this would be to save a pointer to a A::B in each A. This is the pimpl idiom.
The idea of pimpl is to store data in each instance of A without making the internal structure of that data part of A's public interface.
Your code doesn't do that, so it doesn't replace pimpl.
In short, your code is a way to hide helper functions which are implementation details. pimpl does that and ALSO hides helper data which are implementation details.

Using multiple classes within other classes

I'm finishing up a C++ assignment and I'm running into an issue with connecting all the classes together. The classes have basic constructors, getters, setters, etc. so I'm confident the abundance of compiler errors I'm getting are due to me mix and matching all of my Classes incorrectly...
My classes are split up into cpp and h files and I've basically used the include statements every time that class needs something from another class. A basic diagram of which class needs what is shown below:
Basically what I'm trying to figure out is if having #include "Product.h" in both CustomerOrder and Retailer is messing things up or if I'm doing this all the wrong way.
Any help would be lovely!
Thanks!
EDIT:
Here's one instance of what each class is basically doing. The Customer class holds an array of CustomerOrders and CustomerOrders holds an array of Products etc. etc..
...
class Customer
{
private:
string customerName;
string customerID;
float balance;
static const int ORDERSIZE = 2;
CustomerOrder* orderList[ORDERSIZE];
Retailer retailer;
...
and Customer Order:
...
class CustomerOrder
{
private:
static const int SHOPSIZE = 20;
Product* shoppingList[SHOPSIZE];
...
First of all, your diagram is confusing. In OOP, arrows like the one you use indicate public inheritance, but that doesn't seem to be the case here (nor that it should).
Your question cannot be answered generally. You #include another class if you need the complete type. Otherwise, a forward declaration will do. That only has an impact on compilation speed. Nevertheless, the rule is to use forward declarations if you can and #includes if you must.
Here are some cases where you can get away with a forward declaration:
1.) Pointers:
class AnotherClass; // <-- forward declaration
class Example
{
// ...
AnotherClass *another_class;
};
2.) References:
class AnotherClass; // <-- forward declaration
class Example
{
// ...
void f(AnotherClass &another_class);
};
3.) Return values:
class AnotherClass; // <-- forward declaration
class Example
{
// ...
AnotherClass Get();
};
As soon as you are actually using the object of the forward-declared class, you need to have the #include. If you forget, the compiler will remind you.
Caveat 1: Pay attention when you use forward-declared (i.e. so-called "incomplete") types in standard containers. Your compiler may allow this, but it's undefined behaviour to do so!
class Example; // forward declaration
std::vector<Example> v; // undefined behaviour!
Caveat 2: Don't attempt to forward-declare standard classes. Just do #include <vector>, #include <string> and so on and let the compiler figure out how to optimize compile time.
Edit: Actually, the linker, rather than the compiler, will remind you if you forget to include a forward-declared class you cannot forward-declare, but that's just a nitpick :)

c++ object of one class wants to use method of object in another class

I'm converting my old c++ program into OOP and as things grow bigger I'm splitting it per class in .h and .cpp files. The first class compiled nicely into an object file. But my second class is dependant on that first class and now I run into problems. Here my very simplified "all in a single file" code that works:
class A {
public:
void amethod(int) {
....code....
}
};
A a_obj; //object creation
class B {
public
void bmethod(void) {
a_obj.amethod(int);
}
};
B b_obj; //object creation
main() {
b_obj.bmethod();
}
After deviding the code over different files my .h files look like:
//file A.h:
class A {
public:
void amethod(int);
};
//file B.h
#include "A.h"
class B {
public
void bmethod(void);
};
In the implementation of class B there is the call to a_obj.amethod() and even I understand that g++ has no way to know that a_obj is an object of class A as I did not even include the a_obj object creating anywhere in the code.
How to solve this ? Is it something simple that I need to put the object creation somewhere in my .h or .cpp file (note that lots of other classes are using the same amethod()). I can not make everything static as I also have classes with multiple objects (in fact the same way of working is all over the program). Or is this way of working completely wrong (which would explain why I can not find any solution for this).
Is suggest you put more efforts in defining your interfaces.
If class B needs an instance of A to work, use parameters to pass an A:
class B {
public
void bmethod(A & a_obj) {
a_obj.amethod(int);
}
};
main() {
A a_obj;
B b_obj;
b_obj.bmethod(a_obj);
}
The problem is that your original code uses global data (i.e. the declarations of a_obj and b_obj are global). Globals are generally a bad idea because they can cause several problems. The 'proper' OOP way to do it would be to instantiate those objects in main(), and pass them to whatever other objects need to access them. You could pass references, pointers, or copies, depending on your needs.
With that said, if you really want to continue doing it with global data, then you can use an extern declaration. In each *.cpp file where you access a_obj, include this:
extern A a_obj;
That basically tells the compiler that there is an object with that name, but it exists somewhere else. I really don't recommend this approach if you're serious about learning OOP though.
I guess you are planning to use a_obj as global variable in other implementation file (.cpp).
So in header file B.h type extern reference to this instance.
extern A a_obj;
This declaration should help compile your B.cpp file. And ask actual instance a_obj during linking.
I didnt try this code, but telling by my experience and my practice(way) of coding. Hope this solution helps, else am sorry.
First, in order to call A::amethod() class B needs the full definition of class A and its amethod(). So you need to #include A.h before B.h in your .cpp files.
Next, if you address concrete a_obj object, you need to specify what that object is in order to link properly. In you first variant it was global object, so if it is what intended you can write: in A.cpp:
A a_obj;
in B.cpp:
extern a_obj;
// here you can call a_obj methods
But if these classes are so related that one calls methods of another, and also as I catched you need several objects of A and B, consider to connect these classes through inheritance:
class B : public A {
public:
void bMethod(int n) {
aMethod(n); // base class method call
}
// ...
or through delegation:
class B {
A m_A;
public:
void bMethod(int n) {
m_A.aMethod(n);
}
// ...
As mentioned earlier the way
void bMethod(A& a) {
a.aMethod();
}
will work, but the language has built-in means to express classes relationships.
How to implement is more design question, you can read more about this in Stroustrup 3rd edition, '24.3.5 Use Relationships'.
In C++ you can also pass a pointer to a member function of one class into the member function of another class to call a method from completely unrelated class (say, some callback), you can use boost::function and boost::bind for this. But it is advanced technique.

C++ object hierarchy - how to manage circular dependencies?

I want to make two classes: an object and an object_manager, but I'm confused about how they should see/include each other. I've heard that it's forbidden for two headers to include each other and if my code dependencies has circles then it's a bad code design and usually it should be like a hierarchy structure (town->house->furniture and furniture shouldn't know about town existence).
But here I have the object_manager which knows and holds all the objects, and the objects should have an option to create new objects, but then they should call the object_manager which will force them to know about it existence and this will create a circle in the structure, which is bad.
It's like one process wants to create a new process by calling the OS system calls, so the OS and the process knows about each other.
Is there a way I can implement this in the right code design, or should it just be bad sometimes?
I thought maybe the objects should have a special place where they will store all their "system calls", and the object_manager will check it from time to time, but maybe there is a better way.
Use forward declaration:
class ObjectManager;
class Object
{
private:
ObjectManager* m_objManager;
....
public:
....
};
In .cpp file you can include the ObjectManager.h
Also instead of ObjectManager make the interface which will give you more abstraction for implementation IObjectManager.
Actually it is possible to implement the two. And no it's not really bad. Here is some partial code.
let's say you have a header file
myobject.h
#ifndef _MYOBJECT
#define _MYOBJECT
// Declare the Object Manager class in it.
class MyObjectManager; // forward declaration
class MyObject {
MyObjectManager manager;
registerSelf(MyObjectManager &m);
}
#endif _MYOBJECT
Now for the ObjectManager header
#ifndef _MYOBJECT_MANAGER
#define _MYOBJECT_MANAGER
class MyObject; // forward declaration
class MyObjectManager {
private:
List list[];
public:
registerObject(MyObject &o);
};
#endif
Implementation of objectmanager
#include <myobject>
#include <myobjectmanager>
MyObjectManager::manageMyObject(MyObject &o) {
list += o; /* etc. */
}
Implementation of object
#include <myobject>
#include <myobjectmanager>
MyObject::registerSelf(MyObjectManager &manager) {
this.manager = manager;
manager.registerObject(*this);
}
There are many cases where classes need to know about each other. The only issue with this is they have to know about each other partially or at least one class does. The way the issue is generally solved is using forward declarations . The only sticky issue is in class A you can't declare a member that has a type of class B only a pointer or a reference to Class B.
class B;
class A
{
B* oB;
};
class B
{
A oA;
}:
Some general recommendations to remove the coupling between headers follow:
Forward Declare what you can. Sometimes your A class uses others classes (X,Y,..) only by passing references or pointers. So in your A.h you can declare methods that use these X,Y return or argument types without the compiler needing to know the complete type. That means that A.h does not need to include X.h or Y.h
Use PImpl idioms, Sometimes the best way to decouple implementation from interface (without using virtual or abstract classes) is doing something like:
Foo.h
class Foo {
struct Impl;
Impl* m_impl;
public:
Foo();
void SomeMethod();
}
Foo.cpp
#include "X.h"
struct Foo::Impl {
/* actual implementation */
...};
Foo::Foo() : m_impl( new Foo::Impl() ) {};
void Foo::SomeMethod() {
m_impl->SomeMethod();
}
What you're describing is an object that can only exist inside another object.
A good way to implement this is with nested classes:
class object_manager {
public:
class object { // object_manager::object. public allows it to be used outside of manager
public:
void foo() {
object* t = construct(); // can call object_manager methods
}
};
private:
object my_objects[5]; // can create objects
static object* construct() { return NULL; }
};
Keep in mind that you can still have 2 cpp files for object and object_manager.
The CPP files can include each other's headers without causing a compile problem (whether it's correct from a design point of view is a different matter, but should be ok in yur case). This means they can call each other's methods, etc.
Regarding the header files, the "object manager" header will most likely include the "object" header because the "object manager" class needs to work with "object" class instances. If the "object" header file needs to know about the "object manager" class, place a forward declaration for the "object manager" in the "object" header file. That way you can use pointers and references to the "object manager" in the "object" header file without creating a circular include dependency.