Creating copies of pointers to objects

Pages: 12
Hey There.

I am trying to create a class called "enemyManager", that well, manages the enemies in my game (deployment, memory deletion, etc.).

Well, for the function that adds an "enemy" class to the manager, I'm having difficulty trying to create a copy of "refEnemy", then putting that copy into an array that manages the enemy data.

Here is the function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Add an enemy to the manager
void enemyManager::addEnemy(enemy *refEnemy, int instances) {
	if ((instances < 1) || (_numEnemies >= EM_MAX_NUM_ENEMIES))	// Just to makesure we don't add any extra stuff
		return;

	int tempVerticesArray[64][2];

	for (int i = 0; i < instances; i++) {
		enemies[_curAvailableSlot]->enemyPtr = refEnemy;	// <-- Issue is right here
		enemies[_curAvailableSlot]->ptrClearedFromMem = false;

		_curAvailableSlot++;
		_numEnemies++;
	}
}


All I know is that I'm putting the address of "refEnemy" into "enemyPtr" right now which is what I don't want. I want it to copy all the data from "refEnemy" to "enemyPtr".

If needed I'll provide the whole header file.

Thanks.
If enemy isn't abstract, enemies[_curAvailableSlot]->enemyPtr = new enemy(*refEnemy);
Wow, thanks, that worked out perfect.
But then you are losing the polymorphism
Wouldn't be better something like
1
2
3
class enemy{
  virtual enemy* clone() = 0;
};
Yes, hamsterman's example will compile, but will not work in practice. The clone pattern is necessary.
ne555 and jsmith, could you elaborate on this please? (Specifically what I'll need to do to copy all the data into "enemyPtr" properly.)

Also, lets say that I have a class called "boss":
1
2
3
4
5
6
7
8
9
class boss : public enemy {
public:
    boss();
    ~boss();

    doStuff();
private:
    _ID;
};


Would I be able to add it to the enemyManger as of right now? Like this:
1
2
3
enemyManager *em = new enemyManager();
boss *b1 = new boss();
em->addEnemy(b1);


Would I need to overload the function at all?
Consider this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Base {
    virtual ~Base() {}
    int x;
    int y;
};

struct Derived : Base {
    int z;
};

void copy_it( Base* b )
{
    Base* copy_of_it = new Base( b );
}

int main()
{
    Derived* d = new Derived;
    copy_it( d );
}


copy_it does what is called "slicing" -- an instance of Derived has two "layers" -- the bottom-most layer is the data members of Base and the topmost layer is the data members of Derived. When copy_it is called, it makes a copy not of the two-layer cake, but only of the bottom-most layer. This is the problem with polymorphism. To solve that problem -- to have copy_it make a complete copy of what is passed to it -- you have to write a virtual clone() method that derived instances must override.
So what would I want to include in my virtual clone() method?

And wouldn't that example code (if compiled and ran) create a memory leak?

EDIT:

I forgot to mention that the "enemy" class contains pointers to a lot of other classes (like "sprite", "sound", etc). So would I want the clone function/method to return clones of these other classes?
Last edited on
The clone() method is quite simple, see below.

Yes, I did not delete copy_of_it, so it would leak. Fixed below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct Base {
    virtual ~Base() {}
    virtual Base* clone() const { return new Base( *this ); }
    int x;
    int y;
};

struct Derived : Base {
    virtual Derived* clone() const { return new Derived( *this ); }
    int z;
};

void copy_it( Base* b )
{
    Base* copy_of_it = b->clone();
    // use copy_of_it ...
    delete copy_of_it;
}

int main()
{
    Derived* d = new Derived;
    copy_it( d );
}


Whether you want to implement a deep copy or a shallow copy is up to your design. If the enemy class owns the pointers, then probably yes, you'll want a deep copy. If sprite and sound are also base classes, you'll need a clone method on them too. If they are not polymorphic, then you don't need the clone() method.

The clone() pattern exists solely to get around the slicing issue that results from casting a pointer up to a base class type and then attempting to copy the entire object through the base class pointer.
Well for my game, the basic variable structure of "enemy" is this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class enemy : public sprite {
public:
	static int sNextEnemyID;

	bool invul;
	int speed;
	int damage;
	int pointValue;

private:
	int _enemyID;
	int _curHealth;
	int _maxHealth;
	bool _isAlive;
	bool _hitNoiseAdded;
	bool _deathNoiseAdded;
	bool _deathSpriteAdded;
	sound *_hitNoise;
	sound *_deathNoise;
	sprite *_deathSprite;
	int _deathSpriteOffsetX;
	int _deathSpriteOffsetY;
	int _deathSpriteTimer;
	bool _deathRoutineStarted;

};


Sprite and Sound are base classes, but as you can see, "enemy" is derived from "sprite".

I'm also using The DarkGDK game library, and each time I create a new sprite, it calls a DarkGDK function where it loads an image file into memory and then creates a sprite for it. Both of the base classes don't contain any pointers.

So I'm guessing a deep copy here?
Last edited on
Who is responsible for freeing the memory allocated to _hitNoise, _deathNoise, and _deathSprite?

If it is the enemy class, then yes, you'll need a deep copy.
In the "enemy" class deconstructer, it uses the "delete" keyword.

Ex:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Enemy class destructor
// cleans up some of the stuff for us
enemy::~enemy() {
	// Delete the hit noise
	if (_hitNoiseAdded)
		delete _hitNoise;

	// Delete the death noise
	if (_deathNoiseAdded)
		delete _deathNoise;

	// Delete the death Sprite
	if (_deathSpriteAdded)
		delete _deathSprite;
}
Okay, sorry for both double-posting and necro-posting.

I got my "clone()" method written for both my "sprite" and "enemy" class, but I'm running into a little bit of a problem.

I'm getting these compiler errors:
1
2
3
4
5
error C2143: syntax error : missing ';' before '*'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2556: 'int *enemy::clone(void)' : overloaded function differs only by return type from 'enemy *enemy::clone(void)' see declaration of 'enemy::clone'
error C2371: 'enemy::clone' : redefinition; different basic types see declaration of 'enemy::clone'


I think it has something to do with my function declarations and definitions.

For "sprite" class: (<- This works weel by itself.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class sprite {
    public:
        // ...

	virtual sprite *clone();

        // ...
};

sprite *sprite::clone() {
    sprite *cpy = new sprite();

    // ...

    return cpy;
}


For "enemy" class: (<- Errors upon compiling.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class enemy : public sprite {
    public:
        // ..

        virtual enemy *clone();

        // ..
};


enemey *enemy::clone() {
    enemy *cpy = new enemy();

    // ...

    return cpy;
}


Any help is really appreciated.

Thanks.
Last edited on
enemey *enemy::clone() { :)
The clone method is supposed to return a pointer to the base class (in this case sprite). You can't modify that prototype.

However it seems a little weird to say that an enemy is a sprite. Wouldn't be better to say that enemy has a sprite?

Edit: sorry about the misinformation.
Thanks for the correction.
Last edited on
No, you can modify the prototype. Remember that the return type of the function is not part of the function's type, so that

1
2
3
4
5
6
7
struct Base{
    virtual int frobnicate() = 0;
};

struct Derived : base {
    virtual float frobnicate() {}
};


makes Derived a concrete class since Derived's frobnicate() is an override of Base's pure virtual method. It's perfectly ok for the derived class therefore to return a pointer to its type instead of the base type.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Base{
	virtual int frobnicate() = 0; //error: overriding 'virtual int Base::frobnicate()'
};

struct Derived : public Base {
	virtual float frobnicate() {} //error: conflicting return type specified for 'virtual float Derived::frobnicate()'
};

int main(int argc, char *argv[]) {
	Base *b;
	b = new Derived;
	b->frobnicate();
	return 0;
}
Sorry, doesn't like the int/float thing, but replacing int with Base* and float with Derived*, it compiles fine.
Sorry, my bad.

If you replace "int" with "Base*" and "float" with "Derived*" (then return 0) it compiles fine.
@simeonz
Thanks. (Wow I feel like and idiot.)

@Ne555
The reason why I derived "enemy" from "sprite" is that the original class for "enemy" contained many similar things that "sprite" had, so why not just derive it. Lot of work saved.

Thanks everyone.
Pages: 12