I am writing a program that reads documents from a data base and turns the contents into C++ class instantiations. In each document there is a "type" field that I am mapping to a particular C++ class. Basically I read the document, construct an object of the corresponding class, and fill out the fields of the class object. I have maybe 10-15 different types of classes because the types of data in each document may be different, although some of the types are common. The common types of data are reflected in base/derived class definitions. Right now I have a switch statement with case statements corresponding to the different types of objects and in each case statement I create the right kind of object and then fill it in. It is a little messy though.
I was wondering if there is a means to place the various class definitions in an array so that I can mostly get rid of the switch statement. My ideal code would look like:
auto * obj = new arrayOfClassDefinitions[typeofClassIndex]
where arrayOfClassDefinitions contains the names of a set of classes. The obj pointer would then point to a new instantiation of the desired class.
I recall I could do things like this in Python but I am not sure about C++.
any ideas??
If you can organize all your classes into one hierarchical tree, you could use Abstract factory pattern to get similar result. This is example:
#include <map>
#include <memory>
class IBaseClass {
public:
virtual ~IBaseClass(){}
};
class A : public IBaseClass {
public:
// ....
};
class B : public IBaseClass {
public:
// ....
};
class C : public IBaseClass {
public:
// ....
};
class IFactory {
public:
virtual ~IFactory(){}
virtual IBaseClass* create() = 0;
};
template <class T>
class SimpleFactory :
public IFactory {
public:
IBaseClass* create() override {
return new T();
}
};
template <typename T>
std::shared_ptr<IFactory> make_factory() {
return std::make_shared<SimpleFactory<T> >();
}
int main(int, char**)
{
std::map<int, std::shared_ptr<IFactory>> factories = {
{1, make_factory<A>()},
{2, make_factory<B>()},
{3, make_factory<C>()}
};
// ....
int type_index = 1;
auto obj = factories[type_index]->create();
// ...
// don't forget to delete
delete obj;
return 0;
}
Related
I recently started with c++ development. I've come to a problem of which I am not able to solve, given that I am unaware if the following is possible.
I want to create a mapping between a number and class, which are derived from an abstract class.
Essentially what I would like to be able to do is create a factory method that can create a new instance of a class based on a given number associated with that class.
I know that I could do the following...
Vehicle *Vehicle::from_type(byte type)
{
switch(type)
{
case 0x00: return new Bicyle();
case 0x01: return new Car();
...
case 0x10: return new Truck();
}
return null;
}
..., but I'd rather not as I want to keep it DRY.
It there a way where one can do something along the lines of this:
// I know this is incorrect syntax
const map<byte, class extends Vehicle> VEHICLE_MAPPING = {{0x00, Bicyle}, {0x01, Car}, ..., {0x10, Truck}};
Vehicle *Vehicle::from_type(byte type)
{
return new VEHICLE_MAPPING[type]();
}
I can see how your approach could work with usage of std::map<uint8_t, std::unique_ptr<Vehicle>>, but there is a problem - you wouldn't be able to initialise that map with initializer_list, since it copies the elements and, as we all know, std::unique_ptr cannot be copied. You would have to create an init() function to initialise the map that would use similar logic to your Vehicle *Vehicle::from_type(byte type), which would simply be pointless given you already have your function.
Furthermore, I disagree that your first solution violates DRY. It is actually correct in a sense that you won't be forced to use switch or ifs elsewhere in the code. I'd definitely stick with it.
The final note - you could use std::map<uint8_t, std::shared_ptr<Vehicle>> instead of std::map<uint8_t, std::unique_ptr<Vehicle>> and initialise it with initializer_list, since std::shared_ptr can be copied, but I wouldn't advise that since it wrongly indicates the usage of shared_ptr. If you somehow feel forced to do so, here is an example:
class Base{ public: virtual ~Base() = default; };
class Derived1 : public Base{};
class Derived2 : public Base{};
class derived_factory{
private:
derived_factory();
static inline std::map<uint8_t, std::shared_ptr<Base>> base_map = {
{0x00, std::make_shared<Derived1>()},
{0x01, std::make_shared<Derived2>()}
};
public:
static std::unique_ptr<Base> from_type(uint8_t type)
{
return std::make_unique<Base>(*base_map[type]);
}
};
int main()
{
auto ptr = derived_factory::from_type(0x00);
// ptr is of a type std::unique_ptr<Base> and points to Derived1 object
}
Additional note that should be a final discouragement of using this solution is that it's quite slow. It constructs the objects in a map and does nothing with them except for keeping them as 'templated' copy examples.
If they're all derived from a base class, you can use the factory pattern, e.g., from Loki's implementation (see Modern C++ Design for the details, though that book is pre-C++11).
The following creates some concrete vehicles and puts them in a vector and then calls the drive() method on each of them:
#include <iostream>
#include <memory>
#include <vector>
#include "factory.h"
struct Vehicle
{
virtual ~Vehicle() = default;
virtual void drive() = 0;
};
struct Car : Vehicle
{
static constexpr auto ID = 1;
void drive() override { std::cout << "Car\n"; }
};
struct Truck : Vehicle
{
static constexpr auto ID = 2;
void drive() override { std::cout << "Truck\n"; }
};
// Create the factory object
auto g_factory = MyUtil::Factory<std::unique_ptr<Vehicle>, int>{};
void RegisterTypesWithFactory()
{
// We pass in creator functions for each type. Note that these
// could be lambdas or some other freestanding function and they
// could accept parameters.
g_factory.Register( Car::ID, &std::make_unique<Car> );
g_factory.Register( Truck::ID, &std::make_unique<Truck> );
}
int main()
{
// Configure the factory
// Note: Registration can be done any time, e.g., later based on input
// from a file. I do them all at once here for convenience of illustration.
RegisterTypesWithFactory();
// Create some objects with the factory
auto vehicles = std::vector<std::unique_ptr<Vehicle>>{};
vehicles.emplace_back( g_factory.Create( Car::ID ) );
vehicles.emplace_back( g_factory.Create( Truck::ID ) );
// Do something with the objects
for( const auto& v : vehicles )
{
v->drive();
}
}
Which prints:
Car
Truck
See it run live on Wandbox.
You may have heard of the Entity Component System, where everything is an Entity and each entity has a list of Components which control its functionality.
I am trying to find out how to store different objects (each inherit Component) in an array and be able to get an object out of that array based on their type.
The first solution I can think of would be to have an enum for the types of objects inheriting component:
enum ComponentType : unsigned char // There will never be more than 256 components
{
EXAMPLE_COMPONENT,
ANOTHER_EXAMPLE_COMPONENT,
AND_ANOTHER_EXAMPLE_COMPONENT
};
Then Component base class has a ComponentType type; with a getter, and each child component sets its type e.g:
ExampleComponent::ExampleComponent()
{
type = EXAMPLE_COMPONENT;
}
And then I'd have a GetComponent function:
Component* Entity::GetComponent(ComponentType type)
{
for (unsigned int i = 0; i < m_components.size(); i++)
{
if (m_components.at(i).GetType() == type)
{
return &m_components.at(i);
}
}
return nullptr;
}
// Note: m_components is an std::vector;
And then finally you would call GetComponent e.g:
(ExampleComponent*) component = entity.GetComponent(EXAMPLE_COMPONENT);
The problem with this is that you need an enum for each type of component and you also have to cast the component after using GetComponent to make sure you can access its own member variables.
Does anyone know of a proper way of doing this where there is no need for an enum and there is no need to cast the component? If there is a solution that still requires a type variable to be stored in each component it preferably would be a byte and can't be any bigger than 4 bytes.
Edit: I also don't want to use templates
Thanks in advance!
David
Your approach simulates polymorphism: Having the type as a member and an if statement checking for that type is typically a indication to make use of a class hierarchy. You already stated that you want to use objects derived from the Componenttype, so you should also make proper use of polymorphism.
The second problem in your approach is that you want to filter for a "specific type", which more or less is equivalent to a downcast — i.e. a dynamic_cast<>(): When you pass a certain ComponentType to Entity::GetComponent(), it returns a pointer to Component, but the object behind that pointer is always an object of a specific derived class: In your example you always get an ExampleComponent object, when you pass EXAMPLE_COMPONENT to that function.
The following question arises then naturally: What do you want to do with the object returned by this function? You can only call methods from the Component interface/class, but no method from the derived class! So the downcast hardly makes sense at all (it would, if you would return a pointer to an object of a class derived from Component.
Here is how it looks like using polymorphism and with the downcast in the getComponent() method, returning a pointer to a derived class — note that the method is a template to conveniently implement this for every class derived from Component:
#include <string>
#include <vector>
#include <iostream>
class Component {
public:
virtual std::string getType() = 0;
};
using ComponentContainer = std::vector<Component*>;
class AComponent : public Component { public: virtual std::string getType() { return "A"; }; };
class BComponent : public Component { public: virtual std::string getType() { return "B"; }; };
class CComponent : public Component { public: virtual std::string getType() { return "C"; }; };
class Entity {
public:
template <typename T>
T* getComponent();
void putComponent(Component* c) { m_components.push_back(c); }
private:
ComponentContainer m_components;
};
template<typename T>
T* Entity::getComponent()
{
T* t = nullptr;
for (auto i : m_components) {
if ((t = dynamic_cast<T*>(i)) != nullptr)
break;
}
return t;
}
int main()
{
Entity e;
e.putComponent(new AComponent{});
e.putComponent(new BComponent{});
Component* c;
if ((c = e.getComponent<AComponent>()) != nullptr)
std::cout << c->getType() << std::endl;
// delete all the stuff
return 0;
}
The heavy use of dynamic_cast<>() is problematic both from performance and from design point of view: It should only be used rarely, if ever.
So the design problem may be that everything is stored in a single container? You could instead use several containers, based on "behaviour". As behaviour is implemented in an ECS as a derived class or interface, a getComponent()-similar method of this entity would only return objects of certain (sub-)interfaces. These components would then all implement a given interface method, so the need for down-casting would be eliminated.
For example, given you have "drawable components", this suggests the hierarchy:
// Drawable interface
class DrawableComponent : public Component {
public:
virtual void draw() const = 0;
};
// Drawable objects derive from DrawableComponent
class DComponent : public DrawableComponent {
public:
virtual void draw() const { /* draw the D component */ }
};
Then, an entity could have a container of DrawableComponent objects and you would just iterate over those objects and call draw() on each:
using DrawableContainer = std::vector<DrawableComponent*>;
// m_drawables is a memober of Entity with above type
const DrawableContainer& Entity::getDrawables() { return m_drawables; }
// then just draw those objects
for (auto d : entity.getDrawables())
d->draw(); // no downcast!
My question is more or less identical to the one at Need a design pattern to remove enums and switch statement in object creation However I don't see that the abstract factory pattern suits well here.
I'm currently planning the refactoring/reimplementation of some existing DAL/ORM mixture library. Somewhere in the existing code there is code that looks like this:
class Base
{
static Base * create(struct Databasevalues dbValues)
{
switch(dbValues.ObjectType)
{
case typeA:
return new DerivedA(dbValues);
break;
case typeB:
return new DerivedB(dbValues);
break;
}
}
}
class DerivedA : public Base
{
// ...
}
class DerivedB : public Base
{
// ...
}
So the library responsible for database communication populates a struct with all information about the database entity and then the above create() method is called to actually create the corresponding object in the ORM.
But I don't like the idea of a base class knowing of all its derived classes and I don't like the switch statement either. I also would like to avoid creating another class just for the purpose of creating those Objects. What do you think about the current approach? How would you implement this functionality?
This has been discussed here milliions of times. If you don't want to create a separate factory class, you can do this.
class Base
{
public:
template <class T>
static void Register (TObjectType type)
{
_creators[type] = &creator<T>;
}
static Base* Create (TObjectType type)
{
std::map <TObjectType, Creator>::iterator C = _creators.find (type);
if (C != _creators.end())
return C->second ();
return 0;
}
private:
template <class T>
static Base* creator ()
{
return new T;
}
private:
typedef Base* (::*Creator) ();
static std::map <TObjectType, Creator> _creators;
};
int main ()
{
Base::Register <Derived1> (typeA);
Base::Register <Derived2> (typeB);
Base* a = Base::Create (typeA);
Base* b = Base::Create (typeB);
}
Let's say you replace the switch with a mapping, like map<ObjectType, function<Base* (DatabaseValues&)>>.
Now, the factory (which may or may not live in the base class), doesn't need to know about all the subclasses.
However, the map has to be populated somehow. This means either something populates it (so your knowing about all subclasses problem has just been pushed from one place to another), or you need subclasses to use static initialization to register their factory functions in the map.
No matter what you do, you'll need either switch-case or some other construct that will just hide similar logic.
What you can and should do, however, is remove the create method from your Base - you're totally correct it shouldn't be aware of it's derived ones. This logic belongs to another entity, such as factory or controller.
Just don't use enums. They are not OO construction, that was why JAVA did not have them at the beginning (unfortunately the pressure was too big to add them).
Consider instead of such enum:
enum Types {
typeA,
typeB
};
this construction, which do not need switch (another non OO construction in my opinion) and maps:
Types.h
class Base;
class BaseFactory {
public:
virtual Base* create() = 0;
};
class Types {
public:
// possible values
static Types typeA;
static Types typeB;
// just for comparison - if you do not need - do not write...
friend bool operator == (const Types & l, const Types & r)
{ return l.unique_id == r.unique_id; }
// and make any other properties in this enum equivalent - don't add them somewhere else
Base* create() { return baseFactory->create(); }
private:
Types(BaseFactory* baseFactory, unsigned unique_id);
BaseFactory* baseFactory;
unsigned unique_id; // don't ever write public getter for this member variable!!!
};
Types.cpp
#include "Types.h"
#include "Base.h"
#include "TypeA.h"
#include "TypeB.h"
namespace {
TypeAFactory typeAFactory;
TypeBFactory typeAFactory;
unsigned unique_id = 0;
}
Types Types::typeA(&typeAFactory, unique_id++);
Types Types::typeA(&typeBFactory, unique_id++);
So your example (if you really would need this function then):
class Base
{
static Base * create(struct Databasevalues dbValues)
{
return dbValues.ObjectType.create();
}
};
Missing parts should be easy to implement.
I'm facing a problem :
I want to create a function which calls a specific template type constructor depending on a enum that the function will receive. By that i mean :
typedef ____ (Class<whatever>::*tabType)(int flag);
template<typename T>
static Class* Class<t>::createClassInstance(enum precision)
{
static const ___ createTab[] = {
Class<int>,
Class<double>
}
return (new createTab[precision](1));
}
There are a number of ways of achieving this sort of thing, but it sounds like you want to create an array (or map) of factory methods (one for each class), indexed by the enum variable. Each one calls the relevant constructor, and returns a new object of that type.
Of course, for this to make any sense, all of the classes must derive from a common base.
If the enum value is dynamic as a function argument, you'll have to use either a dispatch table or switch/if-else. Notice that your pseudo code does not clearly explain the requirement. Say, what exactly the createInstance function you wish to define and how is it going to be called?
I would say, just construct a std::map that maps the enum to a factory function (boost::function<>). Then you just add one entry for each type that you want, with its corresponding enum. To actually construct the factory functions. You can either have some static Create() function for each class and store a function pointer. Or, you can use Boost.Lambda constructor/destructor functors. Or, you can use Boost.Bind to construct functors that wrap a factory function that requires some number of parameters. Here is an example:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/construct.hpp>
#include <map>
struct Base { };
struct Derived1 : public Base { };
struct Derived2 : public Base {
static Base* Create() { return new Derived2; };
};
struct Derived3 : public Base {
int value;
Derived3(int aValue) : value(aValue) { };
static Base* Create(int aValue) { return new Derived3(aValue); };
};
enum DerivedCreate { ClassDerived1, ClassDerived2, ClassDerived3 };
int main() {
std::map< DerivedCreate, boost::function< Base*() > constructor_map;
constructor_map[ClassDerived1] = boost::lambda::new_ptr<Derived1>();
constructor_map[ClassDerived2] = &Derived2::Create;
constructor_map[ClassDerived3] = boost::bind(&Derived3::Create, 42);
//now you can call any constructor as so:
Base* ptr = constructor_map[ClassDerived2]();
};
I might have made some slight syntax mistakes, but basically you should be able make the above work. Also, the fact that you have several class templates plays no role, once they are instantiated to a concrete class (like Class<int> or Class<double>) they are just like any other class, and the above idea should remain valid.
Extending your example, something like the following works:
enum Prec {INT, DOUBLE};
struct Base
{
virtual ~Base () = 0 {}
};
template<typename T> struct Class : public Base
{
static Base* create (int flag) {return new Class<T> (flag);}
Class (int flag) {}
};
typedef Base* (*Creator) (int flag);
Base* createClassInstance (Prec prec)
{
static const Creator createTab[] = {
Class<int>::create,
Class<double>::create
};
return createTab[prec] (1);
}
int main (int argc, char* argv[])
{
Base* c = createClassInstance (DOUBLE);
return 0;
}
Like the title says, I'm looking for some kind of data structure which will allow me to store any type of class into it that I need at the time. For example:
Foo *foo = new Foo();
Bar *bar = new Bar();
someContainer.push_back( foo );
someContainer.push_back( bar );
someContainer.access( 0 )->doFooStuff();
someContainer.access( 1 )->doBarStuff();
Ideally, as I showed there, it would also allow me to access the contents and use their functions/etc.
I want one of these as I am attempting to create an "invisible" memory management system that just requires a class to inherit my memory manager class, and everything will work automagically.
Here is an example of what I want the code to look like:
template< class T >
class MemoryManaged
{
MemoryManaged()
{
container.push_back( this );
}
void *operator new()
{
// new would probably be overloaded for reference counting etc.
}
void operator delete( void *object )
{
// delete would most definitely overloaded
}
T &operator=( T &other )
{
// = overloaded for reference counting and pointer management
}
static SomeContainer container;
}
class SomeClass : public MemoryManaged< SomeClass >
{
// some kind of stuff for the class to work
};
class AnotherClass : public MemoryManaged< AnotherClass >
{
// more stuff!
};
I hope that my code helps make clear what exactly it is I want to do. If someone knows some kind of already-built data structure that would allow me to do this, that would be awesome. Otherwise, I am currently working on building some kind of shambling zombie of a linked list class that uses templated nodes in order to link any type of class to any other type of class. I still have no idea how I'd get it to work yet, and I would love to be spared the blood, sweat, and tears (and hair) it would take to figure out how to make it work.
Have a common base class for all of your multiple types. Have the data structure hold onto pointers of your base class's type.
Take a look at boost::any and boost::variant.
Would some hybrid of template specialization and double-dispatch help? Something like this:
class IContainable;
class Operation
{
public:
template<class ElementType> void Process(ElementType* pEl) {
// default is an unrecognized type, so do nothing
}
};
class IContainable
{
public:
virtual void OperateOn(Operation* pOperation) = 0;
};
class Foo : public IContainable
{
public:
int GetFooCount() { return 1; }
virtual void OperateOn(Operation* pOperation);
};
// specialization of the operation for Foo's
template <> void Operation::Process<Foo>(Foo* pFoo)
{
std::cout << pFoo->GetFooCount() << std::endl;
}
void Foo::OperateOn(Operation* pOperation)
{
pOperation->Process(this);
}
int main()
{
typedef std::vector<IContainable*> ElementVector;
ElementVector elements;
// configure elements;
Operation oper;
for(ElementVector::iterator it = elements.begin();
it != elements.end(); it++)
{
(*it)->OperateOn(&oper);
}
}
If the list of types in the container isn't known at compile time of the operations of the elements on the container, or they are distributed across modules that are not compiled together, then you could instead use dynamic_cast. You'd define a "IFooHandler" class witha pure virtual method called "HandleFoo" that takes a foo pointer. You'd make Operation::Process virtual and have your operation class derive from both Operation and IFooHandler and implement the operation in HandleFoo(). Your Foo::OperateOn method would dynamic_cast(pOperation) and if the result was non-null, it would call HandleFoo() on the IFooHandler pointer you get from the dynamic cast. Otherwise you'd call the generic Operation::Process and it would have some non-type-specific behavior.
Using a std::vector<T*> should work. Indeed, a new class will be created for each instantiation of MemoryManaged. This means that MemoryManaged<Foo> and MemoryManaged<Bar> will be totally different types. Consequently, the static member container will not be common to these two classes. It will be as if you had the two following classes:
class MemoryManagedFoo
{
MemoryManagedFoo()
{
//Here, you know that 'this' is a Foo*
container.push_back(this); //ok, we add 'this' to a container of Foo*
}
static std::vector<Foo*> container;
};
class MemoryManagedBar
{
MemoryManagedBar()
{
//Here, you know that 'this' is a Bar*
container.push_back(this); //ok, we add 'this' to a container of Bar*
}
static std::vector<Bar*> container;
};
As you can see, the static member is not shared by the two instantiations.
Of course, this solution assumes that MemoryManaged will always be used using CRTP, as you described in your question. In other word, this code will work:
class Foo : public MemoryManaged<Foo> { };
but not this one:
class Foo : public MemoryManaged<Bar>
{
// Here, 'container' is a 'vector<Bar*>' and 'this' is a Foo * --> problem
};