I have created a C++ module which has an API part and an internal part. The API contains a long (more then 30) list of polymorphic classes inheriting directly or indirectly from the same baseclass. In my internal classes/functions these classes are used differently, so I moved some functionality to these classes to be used polimorphically. These functionalites depend on some internal resources, while the internal functions depend on these classes so I broke this circular dependency by forward declaring the necessary classes in the .h
files and including them in the .cpp
files. This way my module compiles and works perfectly.
Here comes the problem. When I include the API from another module, I get "undefined reference to ...." errors to internal functions in the API classes polimorphic functions. I think this is due to the forward declarations. These internal classes are never defined in the eyes of the second module which uses the API.
Broadly my module looks like this:
InternalClass.h:
class ApiObjBase;
class InternalClass {
public:
static InternalClass& get(); // singleton
void processApiObjBase(ApiObjBase& apiObj);
static const Resource& getResource1();
static const Resource& getResource2();
static const std::map<uint64_t, std::unique_ptr<ApiObjBase>>& getApiObjStorage();
UacManager(const UacManager&) = delete; // singleton
UacManager& operator=(const UacManager&) = delete; // singleton
private:
InternalClass(); // singleton
Resource resource1;
Resource resource2;
std::map<uint64_t, std::unique_ptr<ApiObjBase>> ApiObjStorage;
}
InternalClass.cpp:
#include "ApiObjBase.h"
void InternalClass::processApiObjBase(ApiObjBase& apiObj) {
apiObj.internalPolyFunc1();
apiObj.internalPolyFunc2();
// ...
}
const Resource& InternalClass::getResource1() {
return get().resource1;
}
const Resource& InternalClass::getResource2() {
return get().resource2;
}
// Other implementations of member functions ...
ApiObjBase.h:
class InternalClass;
class ApiObjBase {
protected:
int internalVariable1;
int internalVariable2;
int apiVariable1;
int apiVariable2;
public:
ApiObjBase() = default;
// getters, setters
void internalPolyFunc1() = 0;
void internalPolyFunc2() = 0;
void apiPolyFunc1() = 0;
void apiPolyFunc2() = 0;
}
ApiObjBase.cpp:
#include "ApiObjBase.h"
// ...
ApiObjDerived1.h:
#include "ApiObjBase.h"
class ApiObjDerived1 : public ApiObjBase {
protected:
int internalVariable3;
int internalVariable4;
int apiVariable3;
int apiVariable4;
public:
ApiObjDerived1() = default;
// getters, setters
void internalPolyFunc1() override;
void internalPolyFunc2() override;
void apiPolyFunc1() override;
void apiPolyFunc2() override;
}
ApiObjDerived1.cpp:
#include "ApiObjDerived1.h"
#include "InternalClass.h"
void ApiObjDerived1::internalPolyFunc1() {
Resource& res = InternalClass::getResource1(); //
// ...
}
void ApiObjDerived1::internalPolyFunc2() {
Resource& res = InternalClass::getResource1();
// ...
}
void ApiObjDerived1::apiPolyFunc1() {
// ...
}
void ApiObjDerived1::apiPolyFunc2() {
// ...
}
// ...
ApiObjDerived2.h:
#include "ApiObjBase.h"
class ApiObjDerived2 : public ApiObjBase {
protected:
int internalVariable5;
int internalVariable6;
int apiVariable5;
int apiVariable6;
public:
ApiObjDerived2() = default;
// getters, setters
void internalPolyFunc1() override;
void internalPolyFunc2() override;
void apiPolyFunc1() override;
void apiPolyFunc2() override;
}
ApiObjDerived2.cpp:
#include "ApiObjDerived2.h"
#include "InternalClass.h"
void ApiObjDerived2::internalPolyFunc1() {
Resource& res = InternalClass::getResource2();
// ...
}
void ApiObjDerived2::internalPolyFunc2() {
// ...
}
void ApiObjDerived2::apiPolyFunc1() {
// ...
}
void ApiObjDerived2::apiPolyFunc2() {
// ...
}
// ...
SomeOtherModule.cpp:
#include "ApiObjDerived2.h"
void main(int argc, char** argv) {
std::unique_ptr<ApiObjBase> apiObj = std::make_unique<ApiObjDerived2>();
apiObj.get()->apiPolyFunc1();
return EXIT_SUCCESS;
}
For this example the error would the following while linking SomeOtherModule
:
(...) In function `ApiObjDerived2::internalPolyFunc1()':
(...) undefined reference to `InternalClass::getResource2()'
My only idea to this problem is to create wrapper classes (ApiObjBaseWrapper
, ApiObjDerived1Wrapper
, ApiObjDerived2Wrapper
) for each polymorphic class and move all internal member variables and functions to them. These wrapper classes would contain the original derived class as a private member variable, which could be accessed by a virtual getter which returns a reference or a pointer to ApiObjBase
. This would separate the internal and API part of the module making predeclarations unnecessary in the API, while maintaining all the advantages of polymorphism. After this, InternalClass
could use ApiObjBaseWrapper
, and SomeOtherModule
could continue to use ApiObjBase
.
My problem with this idea is that this would require a LOT of new files, classes and code (I would have to create another ~30 classes with .cpp
and .h
files). I cannot emphasize more how big this module is.
What do you suggest, what should I do?