My library uses the Object Factory technique to create "Nodes" that have a specific purpose. By default these Nodes do their job but are quite basic. I want to allow the users of my library to be able and create a sub-class of the provided "Node" class to define their own functionality while keeping the base functionality of a node intact.
Here is some example code to demonstrate my question:
class Node
{
int SomeValue;
public:
Node(int Value)
{
SomeValue = Value;
}
~Node()
{
// Cleanup the node
}
};
class NodeFactory
{
std::vector<Node*> Nodes;
public:
void CreateNode(int Value)
{
Nodes.push_back(new Node(Value));
}
};
This shows the basic Object Factory technique, now for my question.
Can I add a function to the "NodeFactory" such as "void SetType()" and be able to pass in a sub-class of "Node" which in turn will have it create that sub-class during the "CreateNode" function?
Thank you very much for your time it is greatly appreciated.
EDIT:
The usage of "void CreateNode()" is abstracted away from the end user thus my curiosity towards a "void RegisterType()" function where the user can register their sub-class for the factory to create instead of the base-class I provide.
EDIT:
A more concise way to phrase the question would be as follows: How can I let the user tell the factory to create instances of their sub-class, if they've defined one, instead of my default base-class? I want to thank everyone again for their time and effort in answering this question.
I think the problem here is combining the following two requirements:
You want to use the quite simple function void CreateNode(int) to create any node.
You want the user to be able to create new nodes derived from Node and use your factory to create them.
Now what I would suggest is something similar to R Sahu however without following the Factory pattern as strictly as he did.
You could get the functionality you seek by requiring your users to pass a small Creator-object to your factory. (Note that this is deviating a bit from the classical Factory-pattern. As you basically make your NodeFactory into a delegator using the creator-classes.)
class NodeCreator {
public:
virtual Node* create(int) = 0;
virtual ~NodeCreator() = default;
};
class DefaultNodeCreator : public NodeCreator {
public:
virtual Node* create(int value) {
return new Node(value);
}
};
Now I as a user will create my own node:
class MyNode : public Node {
private:
int otherValue;
public:
MyNode(int nodeValue, int otherValue )
: Node(nodeValue), otherValue(otherValue)
{}
// Implement other functionality...
};
class MyNodeCreator : public NodeCreator {
private:
// I added otherNodeValue to show that Creators can have a state.
int otherNodeValue;
public:
MyNodeCreator(int otherNodeValue ) : otherNodeValue(otherNodeValue) {}
virtual Node* create(int value) {
return new MyNode(value, otherNodeValue);
}
};
Now finally in your Factory class you need to set it like this:
class NodeFactory
{
std::vector<Node*> Nodes;
std::unique_ptr<NodeCreator> activeCreator;
public:
NodeFactory() {
setNodeCreator(nullptr);
}
void createNode(int Value)
{
Nodes.push_back( activeCreator->create(Value) );
}
void setNodeCreator( std::unique_ptr<NodeCreator> creator ) {
if (creator == nullptr) {
activeCreator.reset( new DefaultNodeCreator() );
else {
activeCreator.reset(creator);
}
}
};
To use it from main:
int main() {
NodeFactory nf;
nf.createNode(1); // Creating Node(1)
nf.createNode(2); // Creating Node(2)
nf.setCreator( new MyNodeCreator(5) );
// Any nodes created now will be of type MyNode
// with otherNodeValue == 5.
nf.createNode(2); // Creating MyNode(2, 5)
nf.createNode(3); // Creating MyNode(3, 5)
}
A final note:
If you intend for your users to implement subclasses of Node and use these with polymorphism as shown above, it is important that you declare Node's destructor as virtual. You have no guarantee that your users will not use dynamic allocation in their subclasses, so it is your responsibility to ensure that their destructors get called.
A Factory Pattern is meant to create objects with an indirect reference. For example, the user should be able call:
Node* node = Factory::createNode("MyNodeType");
If there is a Factory that can create such a Node, then the function returns with a pointer to a MyNodeType object. Otherwise, it return NULL.
In order for this function to work, a Factory has to be registered that can construct objects of type MyNodeType. We will have to trust that such a Factory creates Nodes of that type.
The classes involved in this patter:
The abstract base class Node.
The abstract base class Factory.
Concrete sub-class of Node called MyNodeType.
Concreate sub-class of Factory. Let's call it MyNodeTypeFactory.
Here's such a skeletal structure.
Node.h:
class Node
{
virtual ~Node() = 0;
};
Factor.h:
#include <string>
class Factory
{
public:
static void registerFactory(std::string const& productType,
Factory* factory);
static Node* creatNode(std::string const& productType);
private:
virtual Node* createNode();
};
Factory.cc:
#include <map>
typedef std::map<std::string, Factory*> FactoryMap;
static FactoryMap& getFactoryMap()
{
static FactoryMap factoryMap;
return factoryMap;
}
static void registerFactory(std::string const& productType,
Factory* factory)
{
getFactoryMap()[productType] = factory;
}
static Node* creatNode(std::string const& productType)
{
FactoryMap& factoryMap = getFactoryMap();
FactoryMap::iterator iter = factoryMap.find(productType);
if ( iter == factoryMap.end() )
{
// Unknown product.
return NULL;
}
return iter->second->createNode();
}
MyNodeType.h:
#include "Node.h"
class MyNodeType : public Node
{
MyNodeType() {}
virtual ~MyNodeType() {}
};
MyNodeTypeFactory.h:
#include <Factory.h>
class MyNodeTypeFactory : public Factory
{
public:
virtual Node* createNode();
};
MyNodeTypeFactory.cc:
#include "MyNodeTypeFactory.h"
struct RegistrationHelper
{
MyNodeTypeFactorHelper()
{
Factory::registerFactory("MyNodeType", new MyNodeTypeFactory());
}
};
static RegistrationHelper helper;
Node* MyNodeTypeFactory::createNode()
{
return MyNodeType();
}
You probably even don't need a RegisterType()... The simplest way is to use C++11 (it allows you to derive nodes w/ different, than a base Node, constructor signatures):
#include <iostream>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
class Node
{
int SomeValue;
public:
Node(int Value)
: SomeValue{Value}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
// ATTENTION Make destructor virtual!
virtual ~Node()
{
// Cleanup the node
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class SomeOtherNode : public Node
{
std::string SomeStringValue;
public:
SomeOtherNode(int Value, const std::string StringValue)
: Node{Value}
, SomeStringValue{StringValue}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~SomeOtherNode()
{
// Cleanup the string node
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class NotARealNode
{
int SomeValue;
public:
NotARealNode(int Value)
: SomeValue{Value}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~NotARealNode()
{
// Cleanup the node
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class NodeFactory
{
std::vector<std::unique_ptr<Node>> Nodes;
public:
template <typename NodeType, typename... Args>
typename std::enable_if<
std::is_base_of<Node, NodeType>::value
>::type CreateNode(Args&&... args)
{
Nodes.push_back(
std::unique_ptr<NodeType>{
new NodeType{std::forward<Args>(args)...}
}
);
}
};
int main()
{
NodeFactory f;
f.CreateNode<Node>(123);
f.CreateNode<SomeOtherNode>(123, "Hello");
#if 0
// ATTENTION It wont compile, cuz NotARealNode is not a child of Node!
f.CreateNode<NotARealNode>(123);
#endif
return 0;
}
Output:
zaufi#gentop>/work/tests> g++ -std=c++11 -o fff fff.cc
zaufi#gentop>/work/tests> ./fff
Node::Node(int)
Node::Node(int)
SomeOtherNode::SomeOtherNode(int, std::string)
virtual Node::~Node()
virtual SomeOtherNode::~SomeOtherNode()
virtual Node::~Node()
You could (should?) use polymorphism for that. Just derive from NodeFactory (make CreateNode a virtual function) and have it spawn Nodes of your desired type. Of course you would have to move the Nodes vector into a different class.
Related
I was assigned to create a sparse matrix. In the process, I got into a problem. I realized I could not access a member of a child class that was stored in a parent class.
I 'googled' my problem and what I got was that there were some casting problems. I tried it out and did not work either.
Sample code:
main.cpp
#include <iostream>
template <typename T>
class Node
{
public: // public for example purposes
Node<T> *down, *right;
public:
explicit Node(Node<T> *d, Node<T> *r) : down(d), right(r) {}
};
template <typename T>
class HNode : public Node<T>
{
private:
unsigned idxValue;
public:
HNode(unsigned iv) : idxValue(iv), Node<T>(nullptr, nullptr) {}
};
template <typename T>
class ENode : public Node<T>
{
public: // public for example purposes
unsigned row;
unsigned col;
int value;
public:
ENode(unsigned r, unsigned c, int v) : row(r), col(c), value(v), Node<T>(nullptr, nullptr)
{}
};
int main(void)
{
Node<int> *root;
root = new Node<int>(nullptr, nullptr);
root->right = new HNode<int>(0);
root->down = new HNode<int>(0);
root->right->down = new ENode<int>(0, 0, 10);
std::cout << root->right->down->value << '\n';
}
This is the error I get:
error: no member named 'value' in 'Node<int>'
std::cout << root->right->down->value << '\n';
root is a Node pointer. root->right is another Node pointer. root->right->down is--you guessed it--a Node pointer.
When you do [...]->value, you're dereferencing that Node pointer, which gives you a Node, and then trying to get the value member on it. But Node has no value member!
You could attempt to cast your Node pointer into an ENode pointer, using dynamic cast. Which would look like:
Node *n = root->right->down;
if(ENode *en = dynamic_cast<ENode*>(n)) {
std::cout << en->value << std::endl;
} else {
std::cout << "That's not an ENode!" << std::endl;
}
But to do this, you'll need to make Node polymorphic (which you can see detailed here).
Also note that in production code, you should be checking to make sure root, root->right and root->right->down are all non-null before going ahead and dereferencing them.
The root class Node only has pointers to other Node's it does not know about what derived classes they might be.
It is "usually" best to have the correct interface in the base class to get results/values from the different kind of derived classes.
So for example if you have a base class animal:
class animal
{
virtual int number_of_limbs() = 0;
}
Then the derived class pig:
class pig: public animal
{
int number_of_limbs() override { return 3;}
}
By doing this the "interface" to the class is generic but each derived/specialisation can have it specific value.
In your case you probably just need a function called virtual int get_value() in your base class and then implement that in your ENode class...
(note all code above is pseudo code only)
I have a class TypedNode to store some data:
template <typename Type>
class TypedNode {
public:
TypedNode() {}
void SetNodeData(Type data) { data_ = data; }
Type GetNodeData() { return data_; }
private:
Type data_;
};
Then I can use it:
int main() {
TypedNode<int> int_node;
TypedNode<double> double_node;
TypedNode<Vector3d> vector3_node;
int_node.SetNodeData(1);
double_node.SetNodeData(2.3);
vector3_node.SetNodeData(Vector3d(4,5,6));;
}
But I want to define a function to access then:
void Access(std::list<TypedNode> node_list) {
for (auto node : node_list) {
node.GetNodeData();
// if it is an integer, do one thing
// if it is a double, do another
}
}
The list needs a concrete class, But I need to store any type of nodes.
Some I changed the code of Node:
class NodeBase {
public:
NodeBase() {}
};
template <typename Type>
class TypedNode : NodeBase {
public:
TypedNode() {}
void SetNodeData(Type data) { data_ = data; }
Type GetNodeData() { return data_; }
private:
Type data_;
};
void Access(std::list<NodeBase> node_list) {
for (auto node : node_list) {
node.GetNodeData();
// if it is an integer, do one thing
// if it is a double, do another
}
}
But the Access() function can only call the methods of Base class.
Despite every derived class have one same name interface SetNodeData, They have a different type. So they are different. They cannot override one same interface in the Base class.
What can I do?
==============================================================
This is my solution:
#include <list>
enum NodeType {
kInt,
kDouble,
kVector3,
};
class NodeBase {
public:
NodeBase() {}
virtual int GetDataInt();
virtual double GetDataDouble();
virtual Vector3 GetDataVector3();
NodeType type() const { return type_; }
protected:
void set_type(NodeType type) { type_ = type; }
private:
NodeType type_;
};
class NodeInt : NodeBase {
public:
NodeInt() { set_type(kInt); }
int GetDataInt() override { return data_; }
double GetDataDouble() override { check(false) << "error"; }
Vector3 GetDataVector3() override { check(false) << "error"; }
private:
int data_;
};
class NodeDouble : NodeBase {
public:
NodeDouble() { set_type(kDouble); }
int GetDataInt() override { check(false) << "error"; }
double GetDataDouble() override { return data_; }
Vector3 GetDataVector3() override { check(false) << "error"; }
private:
double data_;
};
void Access(const std::list<NodeBase>& node_list) {
for (auto node : node_list) {
switch (node.type()) {
case kInt: {
int data = node.GetDataInt();
// do something about int
break;
}
case kDouble: {
double data = node.GetDataDouble();
// do something about double
break;
}
case kVector3: {
Vector3 data = node.GetDataVector3();
// do something about Vector3
break;
}
}
}
}
Your TypedNode template provides no apparent value, it is just a getter and a setter of encapsulated data so it is better to eliminate it for simplicity. What you seem to need is a type that can be int, double or Vector3d so those can be held in same container. For that there is std::variant in C++17. People with substandard compilers can use Boost.Variant that is basically same, just works with C++98 too.
#include <variant>
struct Vector3d {int x, y, z;};
using Node = std::variant<int,double,Vector3d>;
Sure, you can have std::variant<TypedNode<int>,TypedNode<double>,TypedNode<Vector3d>> when there is some vital functionality in it. Posted TypedNode had no functionality, other but more bloat to type.
For accessing variant using same interface there are several ways. For example it can be done using a visitor. Here is a visitor NodeOutput for ostream output of every type in Node.
#include <iostream>
struct NodeOutput {
std::ostream& os_;
NodeOutput(std::ostream& os) : os_{os} {}
void operator()(Vector3d const& v3)
{
os_ << "Vector3d (" << v3.x <<", "<< v3.y <<", "<< v3.z <<")\n";
}
void operator()(double const& d) {os_ << "Double " << d <<"\n";}
void operator()(int const& i) {os_ << "Int " << i <<"\n";}
};
Using such visitor we can write operator<< for Node:
std::ostream& operator<< (std::ostream& os, Node const& v) {
std::visit(NodeOutput{os}, v);
return os;
}
Trying it out. The std::list is rarely used container so here it is replaced with std::vector for simplicity, but it will work similarly with other containers.
#include<vector>
int main()
{
std::vector<Node> nodes;
nodes.emplace_back(42);
nodes.emplace_back(6.66);
nodes.emplace_back(Vector3d{3,2,1});
for (auto& n: nodes) {std::cout << n;}
}
Output:
Int 42
Double 6.66
Vector3d (3, 2, 1)
From what i understand, you basically want to access the overridden functions of the NodeBase. You can still do that with templates. I am not going to suggest code changes on your design because i assume that you oversimplified this to give us an idea of what you want your code to do.
With that said, let's assume that NodeBase class is the base class for NodeInt and NoteDouble. and it looks something like this (slightly simplified compared to yours).
class NodeBase
{
public:
...
virtual void DoSomething()
...
};
class NodeInt : public NodeBase
{
public:
...
virtual void DoSomething() //overridden
{
}
...
};
class NodeDouble : public NodeBase
{
public:
...
void DoSomething()//overriden
{
}
...
};
Let's also assume that our Access function looks like;
template<typename Type, typename A>
void Access(std::list<TypedNode<Type>, A> node_list)
{
for (auto node : node_list)
{
node.DoSomething();
}
}
Note that our Access function can now take any type of list containingTypeNode because of TypedNode<Type>
The job of the Access function is just to call the DoSomething. it shouldn't care what type it is. and it should be deduced based on what to call depending on what we pass as an argument to the Access call.
if a list passed to Access is a type <TypedNode<NodeBase> you
want each node to call, NodeBase::DoSomething();
if a list passed to Access is a type <TypedNode<NodeInt> you want
each node to call, NodeInt::DoSomething();
if a list passed to Access is a type <TypedNode<NodeDouble> you
want each node to call, NodeInt::DoSomething();
To do this, first Instead of inheriting from Base class, lets inherit from a parameterized template argument.
template<typename Type>
class TypedNode : public Type
Next, we want to declare and define the DoSomething function for our TypedNode class.
template<typename Type>
class TypedNode : public Type
{
...
void DoSomething();
...
};
template<typename Type>
inline void TypedNode<Type>::DoSomething()
{
Type::DoSomething();//this is where the magic happens.
}
Notice the Type::DoSomething(); this will allow us to call DoSomething() function of the Generic Base class. One thing to pay attention to is that when we initializing an object using template arguments, the class that is used in the template argument initialization has to have a class member named DoSomething otherwise during compilation we will get an error.
for example;
TypedNode<int> intNode; //wont work because int doesnt have a member DoSomething.
TypeNode<NodeBase> baseNode; //fine.
TypeNode<NodeInt> intNode2; //fine
finally, the main code that produces the outcomes for us.
int main()
{
std::list<TypedNode<NodeBase>> baseNodeList;
std::list<TypedNode<NodeInt>> intNodeList;
std::list<TypedNode<NodeDouble>> DoubleNodeList;
TypedNode<NodeBase> baseNode;
TypedNode<NodeInt> intNode;
TypedNode<NodeDouble> doubleNode;
baseNodeList.push_back(baseNode);
intNodeList.push_back(intNode);
DoubleNodeList.push_back(doubleNode);
Access(baseNodeList);
Access(intNodeList);
Access(DoubleNodeList);
return 0;
}
here is the full code https://ideone.com/2jEmBO
for my project I need to create singletons of a generic type.
Those singletons manage the generic types in a std::map with ID to Object.
Here is my used code:
template <typename tComponent>
class InternalComponent {
public:
static InternalComponent& getInstance() {
static InternalComponent s_result;
return s_result;
}
void add(const tComponent& component, int id) {
m_components[id] = component;
}
void remove(int id) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_components.find(id);
if (it == m_components.end()) {
throw std::runtime_error("Component can't be found.");
}
m_components.erase(it, m_components.end());
}
void replace(const tComponent& component, int id) {
auto it = m_components.find(id);
if (it == m_components.end()) {
throw std::runtime_error("Component can't be found.");
}
m_components[id] = component;
}
tComponent* get(int id) {
return &m_components[id];
}
private:
InternalComponent() {};
InternalComponent(const InternalComponent&);
InternalComponent & operator = (const InternalComponent &);
std::mutex m_mutex;
std::map<int, tComponent> m_components;
};
In order to delete all Components with a specific ID from each singleton, I have to keep track of each created instance of the singleton.
At this point I'm stuck.
The first problem is the generic type which can't be saved to a vector.
I would bypass this with an Baseclass and derive InternalComponent from it.
However I would still be unable to save the references to a vector.
Also I'm unsure how to check if the singleton is created for the first time, without using an if-statement in each getInstance call, to avoid duplicates entries in my list of created singletons.
My final question would be: How can I manage each created instance of an InternalComponent in a single list.
I figured out how I can keep track of all my created template based singleton.
#include <iostream>
#include <vector>
class Base {
public:
virtual void delete(int id) = 0;
};
std::vector<Base*> test;
template<typename T>
class S : public Base
{
public:
void delete(int id) override {
//delete the component
};
static S& getInstance()
{
static S instance;
return instance;
}
private:
S() {
test.push_back(this);
};
public:
S(S const&) = delete;
void operator=(S const&) = delete;
};
int main()
{
S<int>::getInstance();
S<char>::getInstance();
S<char>::getInstance();
for (auto s : test) {
s->delete(666);
}
exit(0);
}
I use an abstract class to later store a template based class inside a vector. The class provides the functions which are later needed. The constructor only gets called once, which allows me to store the this pointer and avoiding uneeded checks.
Basically, I want to automatically register object creator functions with an object factory for a bunch of classes defined across many header files.
The top answer to this post, provides a solution -- but it doesn't fit my constraints.
I'm working on an existing code base. For the classes I need to register, there is already a macro following the class declarations that takes the class as a parameter. If I were able to extend the existing macro definition to also do registration, then it would save a lot time because no existing code would have to be changed.
The closest solution I've been able to come up with is creating a macro that defines a template specialization of a method that registers that object, then calls the previously defined template specialization method -- thus chaining all the register calls. Then, when I want to register all classes, I just call the most recently defined specialization and it registers everything in reverse order of #include appearance.
Below, I've posted a simple working example that shows my solution thus far.
The only caveat is that I have no way of automatically keeping track of the last registered type to call in the chain. So I keep redefining the #define LAST_CHAIN_LINK to be the most recently specialized typename. This means that I'd have to add two lines of #undef/#define after every existing macro call -- I'd really like to avoid that.
The main question:
In the code below, is there any way to define the REGISTER_CHAIN macro to work without using the LAST_CHAIN_LINK #undef/#define code too?
If only it were possible to redefine the LAST_CHAIN_LINK token inside the REGISTER_CHAIN method...
My guess is some solution is possible using the __COUNTER__ preprocessor feature, but that is not available on one of the target platforms (OS X using gcc 4.2.x) and thus not an option.
Simplified example (compiles on GNU C++ 4.4.3):
#include <map>
#include <string>
#include <iostream>
struct Object{ virtual ~Object() {} }; // base type for all objects
// provide a simple create function to derived classes
template<class T> struct ObjectT : public Object {
static Object* create() { return new T(); }
};
struct ObjectFactory {
// pass in creator function pointer to register it to id
static Object* create(const std::string& id, Object* (*creator)() = 0) {
static std::map<std::string, Object* (*)()> creators;
return creator && (creators[id] = creator) ? 0 : creators.find(id) != creators.end() ? (*creators.find(id)->second)() : 0;
}
template<class T = int> struct Register { static void chain() {} };
};
#define LAST_CHAIN_LINK // empty to start
#define REGISTER_CHAIN(T) \
template<> void ObjectFactory::Register<T>::chain() \
{ \
ObjectFactory::create(#T, T::create); \
std::cout << "Register<" << #T << ">::chain()\n"; \
ObjectFactory::Register<LAST_CHAIN_LINK>::chain(); \
}
struct DerivedA : public ObjectT<DerivedA> { DerivedA() { std::cout << "DerivedA constructor\n"; } };
REGISTER_CHAIN(DerivedA);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedA
struct DerivedB : public ObjectT<DerivedB> { DerivedB() { std::cout << "DerivedB constructor\n"; } };
REGISTER_CHAIN(DerivedB);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedB
struct DerivedC : public ObjectT<DerivedC> { DerivedC() { std::cout << "DerivedC constructor\n"; } };
REGISTER_CHAIN(DerivedC);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedC
struct DerivedD : public ObjectT<DerivedD> { DerivedD() { std::cout << "DerivedD constructor\n"; } };
REGISTER_CHAIN(DerivedD);
// Can these next two lines be eliminated or folded into REGISTER_CHAIN?
#undef LAST_CHAIN_LINK
#define LAST_CHAIN_LINK DerivedD
int main(void)
{
// Call last link in the register chain to register all object creators
ObjectFactory::Register<LAST_CHAIN_LINK>::chain();
delete ObjectFactory::create("DerivedA");
delete ObjectFactory::create("DerivedB");
delete ObjectFactory::create("DerivedC");
delete ObjectFactory::create("DerivedD");
return 0;
}
example output:
> g++ example.cpp && ./a.out
Register<DerivedD>::chain()
Register<DerivedC>::chain()
Register<DerivedB>::chain()
Register<DerivedA>::chain()
DerivedA constructor
DerivedB constructor
DerivedC constructor
DerivedD constructor
I find your concept pretty complicated and I'm not sure if it's required. From my point of view your problem can be circumvented when adding the following code:
#include <iostream>
#include <map>
#include <string>
struct Object{}; // Value Object
// provide a simple create function to derived classes
template<class T> struct ObjectT : public Object {
static Object* create() { return new T(); }
};
struct ObjectFactory {
std::map<std::string, Object* (*)()> creators_factory;
static ObjectFactory* instance()
{
static ObjectFactory* __self = NULL;
if (__self == NULL)
__self = new ObjectFactory();
return __self;
}
template <class T> bool reg(const std::string& id, Object* (*creator)() )
{
creators_factory[id] = creator;
return true;
}
// pass in creator function pointer to register it to id
static Object* create(const std::string& id) {
return instance()->creators_factory[id]();
}
};
#define REGISTER_CHAIN(T) bool isRegistered_##T = ObjectFactory::instance()->reg<T>(#T, T::create)
struct DerivedA : public ObjectT<DerivedA> { DerivedA() { std::cout << "DerivedA constructor\n"; } };
REGISTER_CHAIN(DerivedA);
struct DerivedB : public ObjectT<DerivedB> { DerivedB() { std::cout << "DerivedB constructor\n"; } };
REGISTER_CHAIN(DerivedB);
struct DerivedC : public ObjectT<DerivedC> { DerivedC() { std::cout << "DerivedC constructor\n"; } };
REGISTER_CHAIN(DerivedC);
struct DerivedD : public ObjectT<DerivedD> { DerivedD() { std::cout << "DerivedD constructor\n"; } };
REGISTER_CHAIN(DerivedD);
int main(void)
{
// Call last link in the register chain to register all object creators
//ObjectFactory::Register<LAST_CHAIN_LINK>::chain();
delete ObjectFactory::create("DerivedA");
delete ObjectFactory::create("DerivedB");
delete ObjectFactory::create("DerivedC");
delete ObjectFactory::create("DerivedD");
return 0;
}
I hope this helps.
Best regards,
Martin
Using Martin/ #grundprinzip 's suggestion I've been able to solve my problem. I had to modify his approach a bit to allow registration of classes in namespaces.
Thanks Martin!
But, I have a follow-up question now: Isn't it possible the that compiler will entirely optimize out the static ObjectFactory::Register::creator variable (equivalent to is_Registered_##T in #grundprinzip 's code) -- because no code actually references this value?
If so, then optimizing out the variable will optimize out the initialization...thus breaking what I'm hoping to achieve.
Here is the revised code:
#include <map>
#include <string>
#include <iostream>
struct Object{ virtual ~Object() {} }; // base type for all objects
struct ObjectFactory {
static Object* create(const std::string& id) { // creates an object from a string
const Creators_t::const_iterator iter = static_creators().find(id);
return iter == static_creators().end() ? 0 : (*iter->second)(); // if found, execute the creator function pointer
}
private:
typedef Object* Creator_t(); // function pointer to create Object
typedef std::map<std::string, Creator_t*> Creators_t; // map from id to creator
static Creators_t& static_creators() { static Creators_t s_creators; return s_creators; } // static instance of map
template<class T = int> struct Register {
static Object* create() { return new T(); };
static Creator_t* init_creator(const std::string& id) { return static_creators()[id] = create; }
static Creator_t* creator;
};
};
#define REGISTER_TYPE(T, STR) template<> ObjectFactory::Creator_t* ObjectFactory::Register<T>::creator = ObjectFactory::Register<T>::init_creator(STR)
namespace A { struct DerivedA : public Object { DerivedA() { std::cout << "A::DerivedA constructor\n"; } }; }
REGISTER_TYPE(A::DerivedA, "A");
namespace B { struct DerivedB : public Object { DerivedB() { std::cout << "B::DerivedB constructor\n"; } }; }
REGISTER_TYPE(B::DerivedB, "Bee");
namespace C { struct DerivedC : public Object { DerivedC() { std::cout << "C::DerivedC constructor\n"; } }; }
REGISTER_TYPE(C::DerivedC, "sea");
namespace D { struct DerivedD : public Object { DerivedD() { std::cout << "D::DerivedD constructor\n"; } }; }
REGISTER_TYPE(D::DerivedD, "DEE");
int main(void)
{
delete ObjectFactory::create("A");
delete ObjectFactory::create("Bee");
delete ObjectFactory::create("sea");
delete ObjectFactory::create("DEE");
return 0;
}
produces the correct result:
> g++ example2.cpp && ./a.out
A::DerivedA constructor
B::DerivedB constructor
C::DerivedC constructor
D::DerivedD constructor
Suppose I have the following classes:
class BaseObject {
public:
virtual int getSomeCommonProperty();
};
class Object1: public BaseObject {
public:
virtual int getSomeCommonProperty(); // optional
int getSomeSpecificProperty();
};
class BaseCollection {
public:
virtual void someCommonTask();
};
class Collection1: public BaseCollection {
public:
virtual void someCommonTask(); // optional
void someSpecificTask();
};
Each collection, derived from BaseCollection, deals with a specific object type (and only one type). But BaseCollection should be able to perform some tasks that are common to all objects, using only common object properties in BaseObject.
Currently, I have potentially three solutions in mind:
1) Store the objects list in BaseCollection, such as:
class BaseCollection {
vector<BaseObject*> objects;
};
The problem with this solution is that when I need to perform object-specific task in Collection1, I need a dynamic_cast<>, because I don't want to use virtual inherance for specific properties, applying to only one type of object. Considering that dynamic_cast<> could potentially get called millions of time per second, this seems an issue for a performance critical application.
2) Store the objects list in Collection1, such as:
class Collection1: public BaseCollection {
vector<Object1*> objects;
}
But then I need some way to access this object list in BaseCollection, to be able to perform some common tasks on them, ideally through an iterator. I would need to create a function that return a vector for the BaseCollection, but again, this does not seem very efficient, because the only way to do that is to create a new vector (potentially containing thousands of objects)...
3) Store the objects list in BaseCollection AND Collection1:
class BaseCollection {
public:
void someCommonTask(); // Use baseObjects
virtual void addObject() = 0;
protected:
vector<BaseObject*> baseObjects;
};
class Collection1: public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
}
Where the two lists actually contain the same objects. Is that as ugly as it sounds like?
I am looking for the right/correct/best design pattern for this type of problem and none of the 3 solutions exposed above really satisfies me...
Maybe it is possible to solve that problem with templates, but then I don't see a way to store a list of polymorphic collections like this:
vector<BaseCollection*> collections;
You can store all your objects of base and derived classes in one collection through the base class (smart) pointer. Using visitor design pattern and double dispatch mechanism you can call a function only on objects of a specific type without having to expose that function in the base class interface. For example:
#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <stdio.h>
struct Visitor { // Visitor design patter
virtual void visit(struct BaseObject&) {}
virtual void visit(struct Object1&) {}
};
struct BaseObject {
unsigned ref_count_; // intrusive_ptr support
BaseObject() : ref_count_() {}
virtual ~BaseObject() {}
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
void intrusive_ptr_add_ref(BaseObject* p) { // intrusive_ptr support
++p->ref_count_;
}
void intrusive_ptr_release(BaseObject* p) { // intrusive_ptr support
if(!--p->ref_count_)
delete p;
}
struct Object1 : BaseObject {
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
void getSomeSpecificProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class T, class Functor>
struct FunctorVisitor : Visitor {
Functor f_;
FunctorVisitor(Functor f) : f_(f) {}
void visit(T& t) { f_(t); } // apply to T objects only
template<class P> void operator()(P const& p) { p->accept(*this); }
};
template<class T, class Functor>
FunctorVisitor<T, Functor> apply_to(Functor f)
{
return FunctorVisitor<T, Functor>(f);
}
int main()
{
typedef boost::intrusive_ptr<BaseObject> BaseObjectPtr;
typedef std::vector<BaseObjectPtr> Objects;
Objects objects;
objects.push_back(BaseObjectPtr(new BaseObject));
objects.push_back(BaseObjectPtr(new Object1));
for_each(
objects.begin()
, objects.end()
, boost::bind(&BaseObject::getSomeCommonProperty, _1)
);
for_each(
objects.begin()
, objects.end()
, apply_to<BaseObject>(boost::bind(&BaseObject::getSomeCommonProperty, _1))
);
for_each(
objects.begin()
, objects.end()
, apply_to<Object1>(boost::bind(&Object1::getSomeSpecificProperty, _1))
);
}
Output:
$ ./test
virtual void BaseObject::getSomeCommonProperty()
virtual void Object1::getSomeCommonProperty()
virtual void BaseObject::getSomeCommonProperty()
void Object1::getSomeSpecificProperty()
I think you should go for option 1 but use a static cast instead. After all the derived collection knows the type of the member variable for sure.
This answer explains it very well.
Id use nested adapter as in below example. You have to specialize it for every class you want to do a fancy update
!The example has memory leak - allocated A, B, Q objects are not deleted!
#include <iostream>
#include <vector>
#include <algorithm>
class Q
{
public:
virtual void Foo()
{
std::cout << "Q::Foo()" << std::endl;
}
};
class A
{
public:
virtual void Foo()
{
std::cout << "A::Foo()" << std::endl;
}
};
class B : public A
{
public:
virtual void Foo()
{
std::cout << "B::Foo()" << std::endl;
}
virtual void BFoo()
{
std::cout << "B::BFoo()" << std::endl;
}
};
template <typename ElementType>
class C
{
public:
template <typename T>
void add(T* ptr){m_Collection.push_back(std::unique_ptr<Adapter>(new ConcreteAdapter<T>(ptr)));}
void updateAll()
{
std::for_each(m_Collection.begin(), m_Collection.end(), [&](std::unique_ptr<Adapter> &adapter)->void{adapter->update();});
}
private:
class Adapter
{
public:
virtual ElementType* get() = 0;
virtual void update(){get()->Foo();}
};
template <typename T>
class ConcreteAdapter : public Adapter
{
public:
ConcreteAdapter(T* ptr) : m_Ptr(ptr){}
virtual T* get(){return m_Ptr;}
protected:
T* m_Ptr;
};
template <>
class ConcreteAdapter<B> : public Adapter
{
public:
ConcreteAdapter(B* ptr) : m_Ptr(ptr){}
virtual B* get(){return m_Ptr;}
virtual void update()
{
get()->Foo();
get()->BFoo();
}
private:
B* m_Ptr;
};
std::vector<std::unique_ptr<Adapter>> m_Collection;
};
int main()
{
C<A> c;
c.add(new A());
c.add(new B());
//c.add(new Q()); //error - correct
c.updateAll();
return 0;
}
Maybe this will do the trick here ?
class CollectionManipulator {
public:
void someCommonTask(BaseCollection& coll) {
for(unsigned int i = 0; i < coll.size(); i++)
someCommonTask(coll.getObj(i));
}
private:
void someCommonTask(BaseObject*); // Use baseObjects
};
class BaseCollection {
friend class CollectionManipulator;
private:
virtual BaseObject* getObj(unsigned int) = 0;
virtual unsigned int size() const = 0;
};
class Collection1 : public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
private:
BaseObject* getObj(unsigned int value) {
return object[value];
}
unsigned int size() const {
return objects.size();
}
}
If you want abstract your container in Collection1 (like using list instead using vector), to use it in Manipulator, create an abstract iterator...
I think the solution should be a mix of factory method pattern and template method pattern. Take a look at those to refine your design.
Edit: Here is a sample code. GenericProduct is the BaseObject, it provides two methods, one that is general (though it could be overridden), and a specific method which does nothing, it is not a pure virtual so this class can be instantiated. SpecificProduct is a subclass, which implements the specific method in some way.
Now, Factory class is an abstract class that defines an interface for creating specific products by specific factories, it defines a pure virtual method createProduct which creates the product. Two concrete factories are created GenericFactory and SpecificFactory which create specific products.
Finally, the Consumer abstract class (which corresponds to BaseCollection in your code), it defines a pure virtual method for creating a factory createFactory in order to force subclasses to create their own concrete factories (and hence, the correct products). The class also define a method fillArray (prototype pattern) to fill the array with products created by the factory.
#include <iostream>
#include <vector>
using namespace std;
class GenericProduct{
public:
virtual void getSomeCommonProperty()
{
cout<<"Common Property\n";
}
virtual void getSomeSpecificProperty()
{
cout<<"Generic Has Nothing Specific\n";
}
};
class SpecificProduct : public GenericProduct{
public:
virtual void getSomeSpecificProperty()
{
cout<<"Specific Product Has a Specific Property\n";
}
};
class Factory
{
public:
virtual GenericProduct* createProduct() = 0;
};
class GenericFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new GenericProduct();
}
};
class SpecificFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new SpecificProduct();
}
};
class Consumer
{
protected:
vector<GenericProduct*> gp;
Factory* factory;
protected:
virtual void createFactory() = 0;
public:
void fillArray()
{
createFactory();
for(int i=0; i<10; i++)
{
gp.push_back(factory->createProduct());
}
}
virtual void someCommonTask()
{
cout<<"Performaing a Common Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeCommonProperty();
}
}
virtual void someSpecificTask()
{
cout<<"Performaing a Specific Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeSpecificProperty();
}
}
};
class GenericConsumer : public Consumer
{
virtual void createFactory()
{
factory = new GenericFactory();
}
};
class SpecificConsumer : public Consumer
{
virtual void createFactory()
{
factory = new SpecificFactory();
}
};
int main()
{
Consumer* c = new GenericConsumer();
c->fillArray();
c->someCommonTask();
return 0;
}