Thread: what would be an appropriate design pattern?

  1. #1
    Registered User
    Join Date
    Aug 2001
    Posts
    244

    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.
    Last edited by Raven Arkadon; 07-13-2006 at 05:53 PM.
    signature under construction

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    > i hope there are better solutions than that one
    Maybe, but what are you really trying to accomplish?

  3. #3
    Registered User
    Join Date
    Aug 2001
    Posts
    244
    basically defining an interface where the methods may return arbitrary objects which implement a certain interface.

    let's look at that IExpression interface again.
    let's assume the operator+ is defined the following way:
    (note that any object called XXXExpression is assumed to inherit the IExpression interface)
    Code:
    AnyExpression AdditionExpression::operator+ (const IExpression &_r_rhs)
    {
      // in case _r_rhs is just a wrapper object (e.g. AnyExpression)
      // extract the a pointer to the actual object
      IExpression &r_rhs = *_r_rhs.get_original_object();
    
      if(typeid(ErrornousExpression) == typeid(r_rhs)) {
        return ErrornousExpression();
      }
      else {
        return AdditionExpression(*this, r_rhs);
      }
    }
    now AdditionExpression may already return different types (AdditionExpression and ErrornousExpression).

    what i want to do is:
    Code:
    void func()
    {
      // look up the expressions associated with some id.
      // (assume this symbol table simply maps id's to expressions)
      AnyExpression foo = symbol_table.lookup_associated_expression("foo");
      AnyExpression bar = symbol_table.lookup_associated_expression("bar");
    
      // foo and bar are of type AnyExpression which just wrap the "actual" expression
      // (e.g. AdditionExpression, MultiplicationExpression, ...)
      // so in the next line, the operator+ of the wrapped foo object is called.
      AnyExpression result = foo + bar;
    
      // i don't care the "actual" type of result. just calculate some more.
      // if something is wrong with one of the operands, the implementation of
      // the operator+ will handle it, maybe print an error message, and return
      // an ErrornousExpression, which can be used as an operand for further
      // expression objects. (all expressions must "handle" ErrornousExpression then -
      // well they don't have much todo - simply return an ErrornousExpression in that case)
    
      result = result + foo;
      result = result + result;
    ...
      // if anything wen't wrong, then result wraps an ErrornousExpression here.
    
    
      symbol_table.insert("result", result);
    }
    i guess a good use for that would also be in parsers.
    now consider this simple parser:
    when the parser reads an id, it should map it to an expression.
    when the parser reads a "operand1 '+' operand2", where the (non-terminal) operand is associated with an expression it should simply perform the following action: result.expression = operand1.expression + operand1.expression.
    (where x.expression is an AnyExpression)

    if something goes wrong here, then result.expression will simply contain an ErrornousExpression object.
    in case it is some other expression, it will deal with these too.
    signature under construction

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. What design pattern to use here?
    By h3ro in forum C++ Programming
    Replies: 1
    Last Post: 04-15-2009, 06:41 PM
  2. Replies: 7
    Last Post: 09-13-2008, 07:00 PM
  3. Virtual function design pattern
    By George2 in forum C++ Programming
    Replies: 6
    Last Post: 03-19-2008, 07:18 AM
  4. Cprog tutorial: Design Patterns
    By maes in forum C++ Programming
    Replies: 7
    Last Post: 10-11-2004, 01:41 AM
  5. text pattern recognition
    By mtsmox in forum C++ Programming
    Replies: 5
    Last Post: 02-27-2002, 08:38 AM