CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 2 of 2
  1. #1
    Join Date
    Feb 2008
    Posts
    53

    getting all members of a base class from an array

    here is a problem I was unable to find a good solution for in Java. I'm wondering if there's a way you can do it in C++.

    Suppose you have a game thats divided into rooms, and each room has an array of pointers to all the objects in the room. Each object in the room is a subclass of GameObject, and so the room has a GameObject pointer array

    Now suppose you use inheritance to organize your objects into different groups, such as SolidObject (objects you can't walk through) Enemies, Projectiles, items, etc. and suppose you want to get all the objects in the room (contained in the GameObject array) that are members of one of those groups (all instances of that class, and its subclasses).

    I would be nice to write a function to do this, you basically need to check each item in the array to see if it is an instance of the class you are looking for. The only problem is, the mechanism that allows you to do this, namely 'instance_of' in java, 'dynamic_cast' in C++, both take a class name as an argument, and class names (to my knowledge) cannot be passed as an argument to a function. Therefore, every time I need to get all the members of a base class from the array, i have to write a for loop right then and there so I can explicitly give the class name with the cast operation. This is how I was forced to do it in java. Is there a better way this can be done in C++?

  2. #2
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    Re: getting all members of a base class from an array

    Take a look at the visitor pattern. Using this design pattern you can identify objects by method overloading (it´s also called double dispatching).

    Code:
    class IVisitor
    {
    public:
       IVisitor();
       virtual ~IVisitor();
    
       virtual void visit( MonsterObj& obj ) = 0;
       virtual void visit( TreasureObj& obj ) = 0;
    };
    
    class GameObj
    {
    public:
       GameObj();
       virtual ~GameObj();
    
       virtual void accept( IVisitor& Visitor ) = 0;
    };
    
    class MonsterObj : public GameObj
    {
    public:
       MonsterObj();
    
       void accept( IVisitor& Visitor )
       {
          // 2nd step of double dispatching
          Visitor.visit( *this );
       }
    };
    
    class TreasureObj : public GameObj
    {
    public:
       TreasureObj();
    
       void accept( IVisitor& Visitor )
       {
          // 2nd step of double dispatching
          Visitor.visit( *this );
       }
    };
       
    
    class MonsterFilter : public IVisitor
    {
       std::vector<MonsterObj*> m_Monsters;
    
    public:
       MonsterFilter( const std::vector<GameObj*>& Objects )
       {
          for( const std::vector<GameObj*>::const_iterator it = Objects.begin();
             it != Objects.end(); ++it )
         {
             // 1st step of double dispatching
             it->accept( *this );
         }
    
         void visit( MonsterObj& Obj )
         {
            // insert address of monster into vector
            m_Monsters.push_back( &Obj );
         }
    
         void visit( TreasureObj& Obj )
         {
            // ignore treasure objects, we´re interested in monsters only
         }
    
         std::vector<MonsterObj*>& get_monsters()
         {
             return m_Monsters; 
         }
    };
    
    int main()
    {
       std::vector<GameObj*> AllObjects;
    
       // filter all game objects for monster type objects
       MonsterFilter Filter( AllObjects );
    
       // now MonsterFilter.get_monsters() returns an vector of pointers to 
       // all monster objects of AllObjects
    }
    This technique is preferrable over dynamic_casts, because it helps building more robust applications. Each time you add a new game object you have to search your whole code and add an additional comparison branch wherever it´s needed. The compiler won´t complain if you´re missing a handler for the new object type, so you will most likely notice your application does not behave the way it´s supposed to. If things get even worse this branch is executed very rarely, so you don´t notice it until your application has been shipped to a customer.
    When using the visitor patter you have to modify the IVisitor class by adding a new pure virtual method for the new object type. Now the compiler complains every time it tries to compile a IVisitor-derived class because it´s missing the new method.
    Last edited by GNiewerth; March 5th, 2008 at 12:57 PM.
    - Guido

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured