Derived class discovery at compile time¶
The RegisteredClass
class is a template class that allows to register derived classes into a map. This allows to instaniate derived classes from the base class by its name. This mechanisem is similar to OpenFOAMs runtime selection mechanism. The classes are registered at compile time via static member initialization. Additional explanation can be found at: here and here .
This approach allows to create a plugin architecture where now a derived class can be loaded at runtime. Additionally, it simplifies the runtime selection of a specific class. The derived classes can be created by providing its name, as shown below:
std::unique_ptr<baseClass> derivedClass =
baseClass::create("Name of derivedClass", "Additional arguments",...);
-
template<typename DerivedClass, typename BaseClass, StdFunction CreateFunction>
class RegisteredClass¶ Template struct for registering a derived class with a base class.
This struct provides a mechanism for registering a derived class with a base class.
- Template Parameters:
DerivedClass – The derived class to be registered.
BaseClass – The base class that the derived class inherits from.
CreateFunction – The function pointer type for creating an instance of the derived class.
Public Functions
-
inline RegisteredClass()¶
Constructor for the RegisteredClass struct.
reg needs to be called in the constructor to ensure that the class is registered.
Public Static Functions
-
static inline bool init()¶
Initializes the registration of the derived class with the base class.
This function registers the derived class with the base class by calling the BaseClassRegistry::registerClass() function with the derived class’s name and create function.
- Returns:
True if the registration is successful, false otherwise.
Public Static Attributes
-
static bool reg = NeoFOAM::RegisteredClass<DerivedClass, BaseClass, CreateFunction>::init()¶
Static flag indicating if the class has been registered.
Template specialization for registering a derived class with a base class in NeoFOAM.
This template class is used to register a derived class with a base class in NeoFOAM. It provides a static member variable
reg
which is initialized totrue
when the class is instantiated- Template Parameters:
DerivedClass – The derived class to be registered.
BaseClass – The base class with which the derived class is registered.
CreateFunction – The function pointer type for creating an instance of the derived class.
The BaseClassRegistry
class is a template class that manages the registration of the derived classes and stores the map of the registered classes. The map associates a function with a string that is used to create the derived class.
-
template<typename BaseClass, StdFunction CreateFunction>
class BaseClassRegistry¶ Template struct for managing class registration.
This struct provides a mechanism for registering classes with a given base class and a create function. It maintains a map of class names to create functions, allowing for dynamic class instantiation.
- Template Parameters:
BaseClass – The base class type.
CreateFunction – The type of the create function.
Subclassed by NeoFOAM::finiteVolume::cellCentred::VolumeBoundaryFactory< ValueType >
Public Static Functions
-
static inline bool registerClass(const std::string name, CreateFunction createFunc)¶
Registers a class with the given name and create function.
- Parameters:
name – The name of the class.
createFunc – The create function for the class.
- Throws:
std::runtime_error – if the class name already exists in the map.
- Returns:
true if the class was successfully registered, false if the class name already exists in the map.
-
static inline size_t size()¶
Gets the number of registered classes.
- Returns:
The number of registered classes.
-
static inline auto &classMap()¶
A static method that provides access to a map of creation functions.
This method returns a reference to a static unordered map. The map’s keys are strings, representing class identifiers, and the values are creation functions for those classes. This design ensures that the classMap is initialized
- Returns:
A reference to the static unordered map of class identifiers to creation functions.
Usage¶
The following example shows how to use the RegisteredClass
and BaseClassRegistry
to automatically register derived classes. (details see test_RegisterClass.cpp
).
The createFunction
returns a std::unique_ptr
to its base class and takes an argument list specified by the class interface. Furthermore, the BaseClassRegistry
handles the registration and storage of all classes that have been registered.
// forward declaration so we can use it to define the create function and the class manager
class TestBaseClass;
// define the create function use to instantiate the derived classes
using createFunc = std::function<std::unique_ptr<TestBaseClass>(std::string, double)>;
// define the class manager to register the classes
using TestBaseClassManager = NeoFOAM::BaseClassRegistry<TestBaseClass, createFunc>;
We derive the base class from the TestBaseClassManager
and define the interface that the derived classes must implement. We also define a template alias TestBaseClassReg
that will be used to register the derived classes. The create
function will be used to instantiate the derived classes based on the name provided. The RegisteredClass
function will be used to register the derived classes. The derived classes will implement the interface functions testString
and testValue
.
// interface that needs to be implemented by the derived classes
class TestBaseClass : public TestBaseClassManager
{
public:
template<typename derivedClass>
using TestBaseClassReg = NeoFOAM::RegisteredClass<derivedClass, TestBaseClass, createFunc>;
// create function to instantiate the derived classes
static std::unique_ptr<TestBaseClass>
create(const std::string& name, std::string testString, double testValue)
{
try
{
auto func = classMap.at(name);
return func(testString, testValue);
}
catch (const std::out_of_range& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return nullptr;
}
}
template<typename derivedClass>
bool registerClass()
{
return TestBaseClassReg<derivedClass>::reg;
}
virtual ~TestBaseClass() = default;
// interface that needs to be implemented by the derived classes
virtual std::string testString() = 0;
virtual double testValue() = 0;
// ...
};
The derived classes is registered using the RegisteredClass
function. The derived classes implements the interface functions testString
and testValue
. The create
function is used to instantiate the derived classes based on the name provided in the name
function.
class TestDerivedClass : public TestBaseClass
{
public:
// the constructor is used to register the class
TestDerivedClass(std::string name, double test)
: TestBaseClass(), testString_(name), testValue_(test)
{
registerClass<TestDerivedClass>(); // register the class
}
// must be implemented by the derived classes to register the class
static std::unique_ptr<TestBaseClass> create(std::string name, double test)
{
return std::make_unique<TestDerivedClass>(name, test);
}
// must be implemented by the derived classes to register the class
static std::string name() { return "TestDerivedClass"; }
virtual std::string testString() override { return testString_; };
virtual double testValue() override { return testValue_; };
private:
std::string testString_;
double testValue_;
};
After the classes have been defined, the create
function can be used to instantiate the derived classes based on the name provided.
std::unique_ptr<TestBaseClass> testDerived =
TestBaseClass::create("TestDerivedClass", "FirstDerived", 1.0);