Thread: Copying Abstract classes

  1. #1
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141

    Copying Abstract classes

    How is this usually done? Is doing it at all indictive of a design problem? If so, what is the design solution?

    For example..

    Code:
    #include <list>
    using std::list;
    
    class AbstractSomething {
    public:
            virtual void doSomething()=0;
    };
    
    public RedSomething: public AbstractSomething { 
    // implemented doSomething();
    };
    
    class SomethingWithPokaDots {
    // implemented doSomething();
    };
    
    int main() {
         list<AbstractSomething*> somethingList;
         AbstractSomething* a = new SomethingWithPokaDots();
         AbstractSomething* b = new RedSomething();      
    
         for (int i = 0; i < 10; i++) {
               somethingList.push_back(new AbstractSomething(*a)); // illegal, cannot instantiate AbstractSomething
               somethingList.push_back(new AbstractSomething(*b));  // likewise illegal
          }
          // delete a, b, stuff in list
         return 0;
    }
    What is the best solution to this problem? The only solution I see is make a method like

    AbstractSomething* allocateCopy()=0;

    in the AbstractSomething class that needs to be overridden by each subsequent class. Is there any other solution?
    Last edited by SilentStrike; 01-14-2002 at 03:23 AM.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  2. #2
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    It is illegal because you are trying to instantiate an abstract class.

    >>> new AbstractSomething

    You can't do that. What are you trying to do?

    >>> Is doing it at all indictive of a design problem?

    Probably!
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  3. #3
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    I am writing a BomberMan clone (don't know if you've ever played it). Basically, I want to read in data from a file about the map. The data be from a file that looks like this.

    BombableTile {
    index=0
    unbombedimage=brick.bmp
    bombedimage=ground.bmp
    }

    UnbombableTile {
    index=1
    image=Indestructible.bmp
    }

    PassableTile {
    index=2
    image=ground.bmp
    }

    PassableTile {
    index=3
    image=dirtyground.bmp
    }

    MapData =
    1 1 1 1 1
    1 3 0 0 1
    1 3 0 2 1
    1 0 0 2 1
    1 1 1 1 1

    (Maps are really 16x16 tiles, but that doesn't matter)

    Each number in the MapData corresponds to the tile with the given index.

    The map itself is represented as a matrix of AbstractTile*. Loading from the map is done by first putting each AbstractTile that is read into a vector of AbstractTile* at the given index, and each integer in the MapData into a temporary matrix. The problem lies in the following step. The matrix of AT* is copied (can't do it.. elegantly as least), according to the integer data read from the MapData, and the corresponding Tile descriptions above them. Note that keeping the vector with the original vector won't work, as each tile needs to maintain it's state indepdant of the others.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  4. #4
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    I don't think I am following your thinking! You have a file containing descriptions of the object you want, and another containig a map of where in your matrix, each type of object should be? Perhaps I'm just being a bit dumb today!
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  5. #5
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    It's all one file. Regardless, it's like this.

    There are a certain different number of tiles that the map can have. Each tile refers to a specific state that an object has (more than just the class, values are as important as the type, notice the two different PassableTile, which are both the same type, but are different classes). Each tile (starting state) is assigned an integer index. The indicies are then listed in the data section.

    Here is the trial implementation as of now.

    Code:
    void GameMap::readMap(std::istream &input) {
    	Parse::SimpleParser parser(input);
    	
    	vector<AbstractTile*> tempTileVec(MAP_MAX_UNIQUE_TILES , NULL);
    	Util::Matrix<int> tileIndicies(tileMap.numRows(), tileMap.numCols(), -1);
    	
    	parser.addAction("BombableTile", 
    		new Parse::NaturalVectorParser<AbstractTile, ExplodableTile>(tempTileVec));
    	parser.addAction("PassableTile", 
    		new Parse::NaturalVectorParser<AbstractTile, PassableTile>(tempTileVec));
    	parser.addAction("UnbombableTile", 
    		new Parse::NaturalVectorParser<AbstractTile, IndestructibleTile>(tempTileVec));
    	parser.addAction("MapData", new Parse::StdRead<Util::Matrix<int> >(tileIndicies));
    	
    	parser.read();
    	
    	for (int i = 0; i < tileIndicies.numRows() ; i++) {
    		for (int j = 0; j < tileIndicies.numCols(); j++) {
    			size_t indexIntoTileVec = (size_t) tileIndicies(i,j);
    			if (indexIntoTileVec >= MAP_MAX_UNIQUE_TILES)	{ debugOut << "Error" <<endl; /* ERROR */ }
    			if (indexIntoTileVec < 0)						{ debugOut << "Error" <<endl; /* ERROR */ }
    			if (tempTileVec[indexIntoTileVec] == NULL)		{ debugOut << "Error" <<endl; /* ERROR */ }
     /* only way I figured it possible to copy and allocate new types that were copies of previous types do this 
    was to make the dynCopy() part of the interface of AbstractTile */
    			tileMap(i,j) = tempTileVec[indexIntoTileVec]->dynCopy();
    		}
    	}
    	
    	for (vector<AbstractTile*>::iterator iter = tempTileVec.begin(); iter != tempTileVec.end(); iter++) {
    		delete (*iter);
    		*iter = NULL;
    	}
    }
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  6. #6
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    The first thing I'm going to say is this again...

    >>> Perhaps I'm just being a bit dumb today!

    ... but I really am not understanding what you are trying to do. (Your code contains many references to other things in your program as a whole, (which I don't have time to study I might add!), so does not really help me).

    From your original posting, I gather you have an abstract base class, and some classes derived from that which resolve the abstraction. You have some kind of a map stored in a 16x16 which identifies which kind of object you want stored in another 16x16. The second 16x16 is an array of base class pointers, and you want to copy an instantiated object of one of the derived classes to an element of this array. That is what I think you are trying to do, am I right? If not, try explaining this again - the concept, not the details.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  7. #7
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    You have some kind of a map stored in a 16x16 which identifies which kind of object you want stored in another 16x16. The second 16x16 is an array of base class pointers, and you want to copy an instantiated object of one of the derived classes to an element of this array
    Yeah.. thats it. Although it is not the kind of object (IE, class), but rather the specific instance of the object that I want to populate the base class matrix with copies of.
    Last edited by SilentStrike; 01-14-2002 at 03:53 PM.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  8. #8
    Banned Troll_King's Avatar
    Join Date
    Oct 2001
    Posts
    1,784
    public RedSomething: public AbstractSomething {
    // implemented doSomething();
    };
    Change to:

    Code:
    class RedSomething: public AbstractSomething { 
    // implemented doSomething();
    };
    This compiles:

    Code:
    #include <iostream>
    #include <list>
    using std::list;
    using namespace std;
    
    class AbstractSomething {
    public:
    	virtual ~AbstractSomething() {}
    	virtual void doSomething()=0;
    };
    
    class RedSomething: public AbstractSomething { 
    public:
    	virtual ~RedSomething() {}
    	void doSomething() {cout << "Red" << endl;}
    // implemented doSomething();
    };
    
    class SomethingWithPokaDots: public AbstractSomething {
    public:
    	virtual ~SomethingWithPokaDots() { }
    	void doSomething() {cout << "PokaDots" << endl;}
    // implemented doSomething();
    };
    
    int main() {
         list<AbstractSomething*> somethingList;
         AbstractSomething* a = new SomethingWithPokaDots();
         AbstractSomething* b = new RedSomething();      
    
         for (int i = 0; i < 10; i++) {
               somethingList.push_back(a); // illegal, cannot instantiate AbstractSomething
               somethingList.push_back(b);  // likewise illegal
          }
          // delete a, b, stuff in list
         return 0;
    }

  9. #9
    Blank
    Join Date
    Aug 2001
    Posts
    1,034
    The sign of too much java ...

  10. #10
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    Heh, perhaps Nick. That said, I've never actually cloned an object in all my (limited) Java programming. Or perhaps your referring to the new args to addAction? I don't know.

    I want pointers to unique instances in the list. Modifying an element pointed to by the list shouldn't modify any other object in the list. In the game, each tile must keep track of it's state (Whether or not the tile has been "destroyed", so that players can walk over it or explosions run th, whatever the current frame in the animation is, etc).

    The implementation I posted required the use of a method that allocates a copy itself on the heap, to be overloaded in the derived classes.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  11. #11
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    Well, now we're getting somewhere! So, you have an instance of an object A pointed to by a pointer pA. A is a class derived from your base class B, and you have an array, Array[16], of pointers to B, pB.

    Now, if you want Array[0] to be an instance of an A, you need to use the new operator specifying A, but you can store that directly into the pB type vbecause base class pointers can point to B objects, or anyhting derived from them. Once the object is there, you can asssign the original instance of A to the new object, (if you are using complicated objects, you will almost certainly need to overload the "=" operator to do that).

    So

    pA = new (A);

    Array[0] = new (A);
    *Array[0] = *pA;

    Now Array[0] contains an object of class A, which contains the same information as the original A object, but is a totally independent object. Whatever you do to the objects in the Array, will not affect the originals, or the other array members.

    Have we done it?
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  12. #12
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    The problem with that is I'd have to know about the derived classes to implement it.

    The more I think about it, the more a clone method seems like the best solution.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

  13. #13
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    >>> know about the derived classes to implement it

    Which, of course, in the examples you gave at least, you do!

    >>> the more a clone method seems like the best solution.

    Doesn't assigning with an overloaded "=" operator effectively "clone" an object, (or a better clone, but possibly an unsafe solution, a simple bitwise copy)?
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  14. #14
    geek SilentStrike's Avatar
    Join Date
    Aug 2001
    Location
    NJ
    Posts
    1,141
    That would work, but then I would have to set up some switch-like series where I allocate the object.

    IE, in psuedocode

    for all tiles in data matrix
    get corresponding object in vector

    if corresponding object is pointing to ExplodableTile
    tilematrix(curRow, curCol) = new ExplodableTile(*dynamic_cast<ExplodableTile*>(corr esponding object))

    else if corresponding object is pointing to a PassableTile
    tilematrix(curRow, curCol = new PassableTile(*dynamic_cast<PassableTile*>(*corresp onding object))

    else if corresponding object is a pointing to IndestructibleTile
    tilematrix(curRow, curCol) = new IndestructibleTile (*dynamic_cast<IndestructibleTile*> (corresponding object))

    // for all possible classes

    end for

    There, I am just emulating the polymorphic behavior.. so putting the method in the base class, so as to let the compiler handle all that stuff seems like the best solution.
    Prove you can code in C++ or C# at TopCoder, referrer rrenaud
    Read my livejournal

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Issue with abstract classes
    By DavidP in forum C# Programming
    Replies: 1
    Last Post: 08-18-2008, 03:03 PM
  2. Operators of abstract classes
    By Thanuja91 in forum C++ Programming
    Replies: 1
    Last Post: 11-02-2007, 05:30 AM
  3. Abstract classes
    By cisokay in forum C++ Programming
    Replies: 17
    Last Post: 05-29-2005, 09:39 AM
  4. Replies: 7
    Last Post: 03-10-2004, 04:10 PM
  5. Purpose of Abstract Classes
    By luckygold6 in forum C++ Programming
    Replies: 15
    Last Post: 04-29-2003, 06:24 PM