OpenVPN is a giant header only 'library'. I created a library based on it, which consists of a MyClass.h file that has a class MyClass that uses the headers from OpenVPN. I compile this library as libmy.
The problem is that when I try to use libmy in another project, I'm forced to include MyClass.h, which in turn includes all of the OpenVPN headers. I don't need them, since MyClass hides all OpenVPN-related things. However, since OpenVPN headers have some static variables like static int context_data_index (defined AND declared in header, here), these variables get duplicate definitions when I try to compile my new project.
Let me explain the problem better. This is MyClass.h:
class MyClass {
public:
//lots of 'methods' that hide OpenVPN-related things. Users of these methods dont even know about OpenVPN
private:
//Users of MyClass do not need to know about this unique_ptr, but I'm forced to show it in `MyClass.h`, which is why I get duplicated definitions
#ifndef DO_NOT_INCLUDE_OPENVPN_HEADERS
std::unique_ptr<OpenVPNClient> openVpnClient;
#endif
}
as you can see, the users of MyClass don't have to know anything about OpenVPN objects. I even tried to put an #ifndef clause that conditionally includes std::unique_ptr<OpenVPNClient> openVpnClient; when compiling libmy but does not include when compiling the library that uses libmy, but I got terrible undefined behaviour by doing that. I guess it's because a class must have the same number of objects with the same objects in both the libmy implementation and in my new library.
What can I do about this problem?
Try
namespace my_namespace
{
#include "something.h"
}
One solution to not requiring the users of your class to directly include the OpenVPN headers is to forward declare OpenVPNClient in your header for MyClass like this:
class OpenVPNClient;
For this to work your destructor for MyClass needs to be defined in your translation unit. This could be as simple as adding the following line to your source file for MyClass:
MyClass::~MyClass() = default;
There is more info on how to do this and why it is needed here:
Is std::unique_ptr<T> required to know the full definition of T?
An alternate solution is to use PIMPL with your class and completely hide the OpenVPNClient from the header. There is information on how to use PIMPL here:
https://en.cppreference.com/w/cpp/language/pimpl
In your question you asked about a solution where you used an #ifdef to hide the usage of the OpenVPNClient to users of your class but define it when building your class: I guess it's because a class must have the same number of objects with the same objects in both the libmy implementation and in my new library. You can't have 2 different definitions of the class. This will cause undefined behavior.
Related
what is the best way to handle circular inclusions in the situation where I have a class that communicates with another class, like an API and gets callbacks from that class.
Assume I have a class
.h
class Requestor;
class Api
{
public:
Api();
void Request();
int DoStuff();
private:
Requestor *p_rq_;
};
.cpp
#include "api.h"
#include "requestor.h"
Api::Api()
{
}
void Api::Request() {
this->DoStuff();
}
void Api::ReturnRequestId( int id ) {
this->p_rq->SetLastRequestId( id );
}
and
.h
class Api;
class Requestor
{
public:
Requestor();
void MakeRequest();
void SetLastRequestId( int );
private:
Api api_;
int last_request_id_;
};
.cpp
#include "requestor.h"
#include "api.h"
Requestor::Requestor()
{
}
void Requestor::MakeRequest() {
this->api_.Request();
}
void Requestor::SetLastRequestId( int id ) {
this->last_request_id_ = id;
}
In case requestor sends a request and at some point the api gets an id and wants to pass that back to the requestor, how can I do that without including each others .h file which would lead to circular inclusion?
Assume that I cant simply have the function MakeRequest return the id as I dont want to hold that thread until api gets the id?
I am fairly new to c++ and programming, so I may miss the obvious solution. Since I need to call member functions of each other, it is my understanding that forward declaration does not work here.
Also, Api and Requestor should be separate libraries, so I can't make them one class.
You have two different issues, circular dependency between your classes and multiple inclusion of the same header file.
Multiple inclusion is not caused only by simple circular dependencies, like in your case. The usual way to make sure a header is included once and only once in a source file is to use include guards. Normally a header file looks like this:
#ifndef SOME_UNIQUE_NAME_
#define SOME_UNIQUE_NAME_
... header contents ...
#endif
This ensures that no matter how many times a header gets included in a source file (either directly or indirectly), only the first time its contents are actually included, subsequent inclusions are skipped by the preprocessor due to that macro. The macro name must be unique (for obvious reasons), and it is usually some kind of prefix followed by the header name, e.g. LIBNAME_MODULENAME_REQUESTOR_H_.
A widely used alternative, supported by most modern compilers even if not standard as far as I know, is to use a pragma directive at the beginning of the header:
#pragma once
... header contents
Your other issue is circular dependency between your classes. Here you've already found one way to go around it: your Api class holds a pointer to a Requestor object and not the object itself. This allows you to use a forward declaration in Api.h and not include the full class definition.
The Requestor class however holds an Api object, not just a pointer, so the full Api class definition must be available at the point where the api_ member is declared. So you can't use a forward declaration for the Api class in this case, you must actually include the full definition.
Use
#ifndef __filex__
#define __filex__
At the beginning of each .h and
#endif
At the end.
This way, the .h file is read only once
In OOP, you want to break apart a program into multiple classes.
In C#, you would do as such:
namespace a
{
public class ClassA
{
//Methods...that are defined and have code in them.
}
}
and to use that class, you just do "using namespace a;".
Say I want to create a class in C++, and define them, and put code in them.
class ClassA
{
public:
void methodA();
}
ClassA::methodA()
{
//implementation.
}
To access this implementation, you would just use #include "ClassA.h". I fully understand that, and then you have to implement that code again? That seems counterproductive as I like to spread my project over a lot of classes.
So what would be the proper procedure to implement ClassA and not re-implement all it's methods again?
You don't have to reimplement them in each CPP file, the C++ linker takes care of making sure the definitions get matched together.
All you need is:
A header:
#ifndef FOO_H
#define FOO_H
class Foo{
//Junk goes here
};
#endif
A cpp:
#include "foo.h"
//implementations for junk goes here
void Foo::junk(){
}
And then you can include foo.h. Each cpp will be compiled to a .o file. Than, those .o files are handed to the linker which can figure out where definitions are and piece together the code correctly.
C and C++ have a different way of doing things. As long as you have a declaration for a class, method, or external variable the compiler will happily compile and leave off the actual definition of the methods, classes, etc, for link time. This is simplifying things a lot, but basically the compiler will leave a hint to the linker in the object file, saying that the linker needs to insert the address of the method here.
So you just need to include the "ClassA.h" file and you can compile fine.
Because of this you see some different behavior in C and C++ than you would in C#. For example, in C or C++ it's perfectly fine to have two different items (methods, variables, etc) that are named the same in different files as long as neither one is visible outside the file. Whereas in C# you would have to use different namespaces or different names. Note - not that I'm saying this is good practice, it's just possible.
The .h header files contain the class specification. The corresponding .cpp files contain the implementation and are compiled to .o files. During development, you would include .h files to access the APIs provided by the class. During compilation/linking stage, you would include the .o files also along with your source files to form the final binary. You don't need to implement anything again, w.r.t to the class you are using.
I made a program that has a class with static-only members in it in its own dedicated cpp/h file combo. The probably is that when I try to use these static members in my code, I'm getting "unresolved external" errors at the linker stage. I am remembering to include the h file in my cpp file that is getting the errors. I don't understand. Is this the wrong design approach to take?
Basically i want some global objects that are part of a third party API to be available to my whole program, so I organized everything into one class and made everything a static member. I also made an empty private constructor to keep the class from being instantiated. Is this a sensible approach? The static members are all pointers and I tried to start out by allocating new objects and attaching each to the static poonters. Is here a problem with this approach?
Thanks!
Are you remembering to actually define the variable somewhere, instead of just declaring it in the header?
Foo.hpp:
#ifndef FOO_HPP
#define FOO_HPP
class Foo {
public:
static int bar;
};
#endif
Foo.cpp:
#include "Foo.hpp"
int Foo::bar; // <-- This being the critical line.
If you are accessing global objects in a third-party library, you need to make sure you are linking with that library. Just compiling against the headers for the library won't do it.
Let's say I have a header file with a class that uses std::string.
#include <string>
class Foo
{
std::string Bar;
public:
// ...
}
The user of this header file might not want std::string to be included in his/her project. So, how do I limit the inclusion to just the header file?
The user of your class must include <string>, otherwise their compiler will not know how big a Foo object is (and if Foo's constructors/destructors are defined inline, then the compiler also won't know what constructor/destructor to call for the string member).
This is indeed an irritating side-effect of the C++ compilation model (basically inherited intact from C). If you want to avoid this sort of thing entirely, you probably want to take a look at the PIMPL idiom.
Basically, you don't. Once you've included a file, all of the entities from that file are available for the remainder of the translation unit.
The idiomatic way to hide this sort of dependency is to rely on the pimpl idiom.
That said, why would code using Foo care that <string> was included? All of its entities are in the std namespace (well, except that <string> might include some of the C Standard Library headers, but generally you should code with the expectation that the C Standard Library headers might be included by any of the C++ Standard Library headers).
I don't see how this can be done, or if it's possible in c++. The reason being: when the compiler sees the member of type "std::string", it must know what is the type in order to know its size. This information can only be obtained by looking into the class definition in a .h file.
One way the users can use a different string class in their source, is by using "using" construct:
//This is how users can use an adt with same name but in different namespaces
using std::string;
string bar = "there";
using my_own_lib::string;
string bar1 = "here";
You can't do that. If the user doesn't want to include std::string, then he or she should not use that class at all. std::string will have to be included in the project in order to link your class correctly.
In C# or Java, classes are declared and defined at the same time. In C++, the norm is to do that separately. What if we write the whole class in one , say .cpp, file and include that in files that references to it, what kinds of bad thing technically would happen besides a lengthened compilation process?
If your implementation of MyClass is all in the header file MyClass.h then any file you needed to implement MyClass will be included whenever someone includes MyClass.h.
If you change any part of MyClass.h, even if it's trivial (such as adding a comment or even a space) then all files that include it will have to recompile, even if the interface hasn't changed.
Neither of these matters for toy projects, but as you noted, when you have a program that consists of hundreds (or thousands, etc.) of class files, the added compilation time alone makes it worthwhile to separate out implementation from interface.
For instance, if I have the following:
// MyClass.h
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include "Inventory.h"
class MyClass
{
public:
MyClass();
void processInventory(Inventory& inventory)
{
// Do something with each item in the inventory here
// that uses iostream, iomanip, sstream, and string
}
private:
// ...
};
It would more ideomatically be written as:
// MyClass.h
class Inventory;
class MyClass
{
public:
MyClass();
void processInventory(Inventory& inventory);
private:
// ...
};
// MyClass.cc
#include "MyClass.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include "Inventory.h"
MyClass()::MyClass()
{
}
void MyClass()::processInventory(Inventory& inventory)
{
// Do something with each item in the inventory here
// that uses iostream, iomanip, sstream, and string
}
Notice: Including MyClass.h doesn't mean iostream, iomanip, sstream, string, or Inventory.h have to be parsed. Changing how processInventory works doesn't mean all files using MyClass.h have to be recompiled.
Notice how much easier it can be to figure out how to use MyClass now. Header files serve an important purpose: they show people how to use your class. With the modified MyClass.h it's easy to see the list of functions. If each function is defined in the header, then you can't look at just the list of functions. That makes it harder to figure out how to use the class.
You may break the one definition rule.
If you write this:
class foo
{
public:
void doit();
};
foo::doit() {}
and include that in multiple classes, you will have multiple definitions of foo::doit and your link will fail.
But if you make all your classes inline, either by defining them within the class declaration:
class foo
{
public:
void doit() {
}
};
or by explicitly making them inline:
class foo
{
public:
void doit();
};
inline void foo::doit() {}
then you can include that file as many times as you like.
The linker will see multiple definitions of the class's members when you try to combine multiple such objects. Thus, you won't be able to produce a binary from source files that include anything in more than one place.
Typically you separate the declaration and definition of a class. This allows you to use your class in different source files by simply including the declaration.
If you include a .cpp which has both declaration and definition into 2 different source files then that class will be doubly defined.
Each .cpp that the class is included into will compile fine into object files. However each class must have only 1 definition total or else you will not be able to link your object files together.
The most important thing to understand about #include contrasted with other languages importing methods, is that #include COPIES the contents of that file where the #include directive is placed. So declaring and defining a class in the same file will create three things:
Significantly increase your compile
times.
If your definitions are not inline
you will get linker errors, since
the compiler finds multiple
definitions to the same functions
That would expose the implementation
to the user, instead of only the interface.
That is why it is common practice to define large classes in separate files, and on some ocassions, really small classes with small implementations (like smart pointers) in one file(To also implicitly inline methods).
#Bill
I think it is important to underscore Bill's point:
Notice how much easier it can be to
figure out how to use MyClass now.
Header files serve an important
purpose: they show people how to use
your class.
the .h file being more or less the "public" doc to allow the understanding of how your class works in some ways conceptually--an Interface. Remember the source file should be thought of as proprietary. I remember learning a lot about how Unix worked in my early C/C++ days by reading header files. Also remember that inline function complexities should be no more than accessor's
A big reason for a class to be defined in a cpp-file is that it isn't needed publically, it is just a helper function (like e.g. a functor). Some people seem to be afraid to put the complete class in the cpp-file, while that just shows your intent of only using the class there.
Files are usually the atoms of your version control system - if you partition things sensibly into different files, then it becomes possible for a team of developers to check out only the parts they each need to work on. Put everything in one file and you can't do that.