what would be an appropriate design pattern?
now the problem i have is following:
i have this interface, and the operator + should return an object that is derived IExpression again.
like this:
Code:
class IExpression // an interface
{
public:
virtual IExpression* operator + (const IExpression &r_rhs) = 0;
};
well, returning a pointer isn't really what i want, since then within the implementation of operator+ a new object would have to be created.
so then the caller would have to delete that object again.
also smart pointers arent what i want either, because the objects returned by that interface are lightweight objects anyway.
now i thought, i i could use the boost::any type for that.
the idea is:
.) define an interface - lets call it IFoo
.) create a class called AnyFoo, which
a.) inherits from IFoo
b.) has an boost::any attribute, to hold any other object that was derived from IFoo
c.) defines all methods from the interface IFoo, which call the methods of the wrapped object
here an example:
Code:
#include <iostream>
#include <boost/any.hpp>
// forward declaration of AnyExpression
class AnyExpression;
/**
* IExpresion
*
* interface for expressions
*/
class IExpression
{
public:
virtual AnyExpression operator+ (const IExpression &r_rhs) = 0;
};
/**
* AnyExpression
*
*
* a class that can wrap any object that inherits the IExpression interface
*/
class AnyExpression
: public IExpression
{
protected:
boost::any any;
// p_fn_retrieve is a function pointer to an instance of the retrieve-func
IExpression* (*pfn_retrieve)(AnyExpression &r_this);
/**
* _retrieve
*
* extracts a pointer to an IExpression from the attribute 'any'.
*/
template<typename T>
IExpression* _retrieve(AnyExpression &r_this)
{
return static_cast<IExpression*>(&boost::any_cast<T>(r_this.any));
}
public:
/**
* constructor
*
* objects passed as an argument must inhert the IExpression interface
*/
template<typename T>
AnyExpression(const T &r)
: any(r)
{
static_cast<const IExpression*>(&r); // make sure that r is an IExpression
pfn_retrieve = &_retrieve<T>;
}
AnyExpression operator+ (const IExpression &r_rhs);
};
AnyExpression AnyExpression::operator+ (const IExpression &r_rhs)
{
return pfn_retrieve(*this)->operator+ (r_rhs);
}
now this patterns allows arbitrary objects to be returned and used in a pretty comfortable way.
i'm not sure if this is a good design pattern. but it was the best one i could think of.
but actually it's pretty complicated(*) - are the better solutions?
(*) actually IExpression must have a method to retrieve the this pointer of the original object. so that the this pointer of an object wrapped by AnyExpression can be retrieved.
Code:
IExpression* AdditionExpression::get_original_object()
{
return this;
}
IExpression* AnyExpression::get_original_object
{
return pfn_retrieve(*this)->get_original_object();
}
void some_func(IExpression &_r_arg)
{
// no matter wheter IExpression is actually an AnyExpression or
// an AdditionExpression, both can be used the same way now:
IExpression *p_arg = r_arg.get_original_object();
//edit: so the purpose of that is, to be able to use typeid on the correct object
if(typeid(*p_arg) == typeid(AdditionExpression))...
...
}
hmmmm.... well, what do you think?
i hope there are better solutions than that one :/
edit2: oh and i forgot to mention:
instead of using the boost::any type which does dynamic memory allocation afaik, a class similar to boost::any could be used, which stores the object in a fixed size array - in that case no heap-memory would have to be allocated, if the objects fit into this array directly.