views:

218

answers:

4

Hello,

I've spent my entire day researching this topic, so it is with some scattered knowledge on the topic that i come to you with this inquiry. Please allow me to describe what I am attempting to accomplish, and maybe you can either suggest a solution to the immediate question, or another way to tackle the problem entirely.

I am trying to mimic something related to how XAML files work in WPF, where you are essentially instantiating an object tree from an XML definition. If this is incorrect, please inform. This issue is otherwise unrelated to WPF, C#, or anything managed - I solely mention it because it is a similar concept..

So, I've created an XML parser class already, and generated a node tree based on ObjectNode objects. ObjectNode objects hold a string value called type, and they have an std::vector of child ObjectNode objects.

The next step is to instantiate a tree of objects based on the data in the ObjectNode tree. This intermediate ObjectNode tree is needed because the same ObjectNode tree might be instantiated multiple times or delayed as needed. The tree of objects that is being created is such that the nodes in the tree are descendants of a common base class, which for now we can refer to as MyBase. Leaf nodes can be of any type, not necessarily derived from MyBase.

To make this more challenging, I will not know what types of objects might be involved in the tree, so I need to allow for new types to be registered with the factory.

I am aware of boost's factory. Their docs have an interesting little design paragraph on this page:

o We may want a factory that takes some arguments that are forwarded to the constructor,
o we will probably want to use smart pointers,
o we may want several member functions to create different kinds of objects,
o we might not necessarily need a polymorphic base class for the objects,
o as we will see, we do not need a factory base class at all,
o we might want to just call the constructor - without #new# to create an object on the stack, and
o finally we might want to use customized memory management.

I might not be understanding this all correctly, but that seems to state that what I'm trying to do can be accomplished with boost's factory. But all the examples I've located, seem to describe factories where all objects are derived from a base type.

Any guidance on this would be greatly appreciated.

Thanks for your time!

+2  A: 

Define a typedef for the factory methods, something like:

typedef void* (*FactoryMethod)(const vector<string>& parameters);

In other words, each and every factory method returns a pointer to anything (a pointer to void), and takes as a parameter a const vector of strings.

The registration data looks like:

std::map<string, FactoryMethod> globalFactoryMethods;

... where the key is the type string and the value is a pointer to the corresponding factory method. When you have a new type with a new factory method, 'register' it by adding it to the map (at run-time).

Construction using the registered factory methods might look like this (pseudocode):

foreach (Node node in nodes)
{
  string type = node.type;
  FactoryMethod factoryMethod = globalFactoryMethods[type];
  void* constructedLeaf = (*factoryMethod)(node.nParameters, node.pParameters);
  //do something here with constructed leaf
}

Leaf nodes can be of any type, not necessarily derived from MyBase.

That's a problem in C++: if you don't know what they are, then how will you delete them?

C# (unlike C++) can delete things without knowing what they are, or rather it doesn't need to delete things: because it's managed memory, and everything is a subclass of System.Object.

ChrisW
I'm still working on this issue, though it had to be sidelined for over a week.. I just wanted to let you know that I appreciated your response and will not forget to mark it as an answer if appropriate.
chrensli
A: 

if I think I understood correctly something like this perhaps:

void register(string constructor, void*(*method)(...)); // put in map

template<class T>
T* new_(string subclass, ...) {
  return static_cast<T*>(constructors_[subclass](...));
}
aaa
A: 

I cant really understand your question but from the topic, I think your are trying to create arbitrary registered object, perhaps you can look at design pattern "prototype"
Click here for almighty wiki

YeenFei
A: 

It's a very good thing that you described your problem :)

The idea of having a factory being able to create any kind of type is of course very enticing, however it is both complicated and unnecessary. I understand the appeal of a void* unfortunately it's not as glamourous as it seems. The only thing you can do with such a beast is to cast it into a proper pointer... and this requires knowing what the type is at compile time!

Suppose I have a std::vector<void*> and I ask you to print out the content of this vector, what are you going to do ?

It is perfectly acceptable to force people to have the classes they create inherit from a base class that you design for the very purpose of being easy handled by the factory.

struct Object: boost::noncopyable
{
  virtual Object* clone() const = 0;
  virtual ~Object() {}
};

This is a very small constraint indeed than to require inheritance from this class. In exchange, you gain the virtual destructor and you ensure than the class can be copied polymorphically (thanks to the clone member function) to avoid the problem of object slicing.

I think you should read up on some Design Patterns:

  • Prototype is widely used to implement Factory, though it's not the only way
  • Factory, you seem to already know, perhaps that AbstractFactory would help you too
  • Composite is a must for dealing with trees of objects
  • Visitor really helps to define a forward compatible way to operate on Composite
Matthieu M.
I'm still working on this issue, though it had to be sidelined for over a week.. I just wanted to let you know that I appreciated your response and will not forget to mark it as an answer if appropriate.
chrensli