Sign in to follow this  
Evil Booger

Having problems with destructor of a class object thats in another class object

Recommended Posts

Okay, the problem is that the destructors of my “EnemyShip” objects are not being called. And I am having trouble with this because my “Level” class contains an array of “EnemyShips”. The Level’s destructor runs. I need to know how I can’t force the Level’s destructor to activate the destructors of the EnemyShips. And also, EnemyShip is inherited from “Ship”, that is why in my source code, I give you the destructor of my Ship class. Here is some code. Post if you need more.
Ship::~Ship()
{
	if(surface)
	{
		SDL_FreeSurface(surface);
	}
	if(altsurface)
	{
		SDL_FreeSurface(altsurface);
	}
	if(explosionsurface)
	{
		SDL_FreeSurface(explosionsurface);
	}
	std::cout << "Destructing ship..." << std::endl;
}

class Level
{
public:
	SDL_Surface *background1;
	EnemyShip EnemyShipArray[ENEMYSHIPS_IN_LEVEL];
	//int formation_number;

	Level();
	~Level();
	void ExecuteLevel();
	int FormationDestroyed(int formnum);
	void ActivateFormation(int formnum);
};

Level::~Level()
{
	SDL_FreeSurface(background1);
	std::cout<<"Destructing Level"<<std::endl;
}


Share this post


Link to post
Share on other sites
Is the destructor for the Ship class virtual?

Anyway, if that isn't the problem, you may need to post more code (e.g. the headers for the Ship, EnemyShip, and Level classes).

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Booger
No, its not virtual. Is it supposed to be?
Yeah, it should be virtual (otherwise, the derived class destructors won't be called when the classes are used polymorphically).

However, it looks like you're storing the EnemyShip's by value, so AFAIK the EnemyShip destructor should be invoked no matter what.

I think we may need to see more code...

Share this post


Link to post
Share on other sites
Well the EnemyShip class does not have a destructor, it uses the one from the Ship class.

My first two EnemyShip objects destruct perfectly because they are not associated with the Level object. The fifteen other enemyships are copies of the original two that I create using this function:

void CopyEnemyShips(int num_of_ships,
EnemyShip *e_array,
int start_identifier,
EnemyShip *base_ship)
{
e_array = e_array+start_identifier;

for(int n=0;n<num_of_ships;n++)
{
(e_array + n)->surface = base_ship->surface;
assert((e_array + n)->surface);
(e_array + n)->altsurface = base_ship->altsurface;
(e_array + n)->explosionsurface = base_ship->explosionsurface;

(e_array + n)->laser1.surface = base_ship->laser1.surface;
(e_array + n)->laser2.surface = base_ship->laser2.surface;
(e_array + n)->laser3.surface = base_ship->laser3.surface;
(e_array + n)->laser4.surface = base_ship->laser4.surface;

(e_array + n)->PosRect.x = 64 * n;
(e_array + n)->PosRect.y = 10;

(e_array + n)->shiptype = base_ship->shiptype;

(e_array + n)->SetHealth(base_ship->health);
}
}



And this function is called in my "main()" function (after the surface files are loaded) like this:

CopyEnemyShips(5,level1.EnemyShipArray,0,&Zapper);
CopyEnemyShips(5,level1.EnemyShipArray,5,&Zapper);
CopyEnemyShips(5,level1.EnemyShipArray,10,&Grunt);


Share this post


Link to post
Share on other sites
To force destruction you call 'delete object;' delete will call all the destructors that should be called.

You still did not provide enough code. I would say that the important piece of code is the .h file.

from what you are saying , it seems you are just missing a virtual destructor in your Ship class.

virtual is the implementation of polymorphism in C++. virtual tells the compiler that a call to this function is dynamic. while not using virtual , the calls to the function are static.

so if you only have a class Ship with a function foo(). you dont need to use virtual on this function. the calls to this function will always be static. the same function always gets called.

when you inherit from Ship class with EnemyShip and EnemyShip implement foo(). the call need to become virtual. because now the calls are dynamic. a call to foo() may result to a call for Ship.foo() or EnemyShip.foo(). thats the job of the VTable.

Hope thats help,
Nuno1

Share this post


Link to post
Share on other sites
Ok Nuno, I think I understand what you're saying. But I didn't think that virtual was necessary because my EnemyShip class does not have a destructor, so the only one to call is the Ship's destructor. And this works fine for the EnemyShips that are not in my Level class.

And I don't think there's any more code I can show except for code from my ship class but that's nothing except a nonvirtual destructor declaration.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Booger
But I didn't think that virtual was necessary because my EnemyShip class does not have a destructor

Every class has a destructor, whether you've specified one or not. What Nunu is trying to explain is polymorphism; i.e. you can refer to a derived class through its parent and still call the appropriate functions.

With your project, it would look something like
Ship* someShip = new EnemyShip(args)

Then you could call a function on someShip, and if it is virtual it will be properly redirected to the function in EnemyShip, even though the object referred to is a Ship.

Likewise, if you delete someShip, if the destructor is virtual, then the proper destructor gets called. Otherwise, it will use Ship's destructor and now you have a problem, because the derived class wasn't destructed properly.

What makes you so sure the EnemyShip destructor isn't being called? You're using the compiler-generated one because, like you said, you didn't specify one.

It seems to be that the destructors are indeed being called; they should appear just after the user-defined bit of ~Level is finished. Try adding in a destructor with some output and see what it says.

P.S. I just tested this out. The destructor is indeed called on every instance of EnemyShip in the array.

#include "stdafx.h"
#include <iostream>

class Ship {
public:
Ship() {}
~Ship() { std::cout << "Ship destructing ...\n"; }

private:
};

class ShipContainer {
public:
ShipContainer() { std::cout << "ShipContainer constructed.\n"; }
~ShipContainer() { std::cout << "ShipContainer destructing ...\n"; }
private:
Ship shipArray[5];
};

int _tmain(int argc, _TCHAR* argv[])
{
{
ShipContainer blah;
}

char a;
std::cin >> a;

return 0;
}

Output:

ShipContainer constructed.
ShipContainer destructing ...
Ship destructing ...
Ship destructing ...
Ship destructing ...
Ship destructing ...
Ship destructing ...


Good luck!

Share this post


Link to post
Share on other sites
Ok I understand how the compiler might do the default destructor for my EnemyShip class so I declared the Ship's destructor to be virtual. But it seems both destructors are still occurring.

Here is the output when both destructors have the same code except that the output says "enemyship" on one and "ship" on the other:

Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Creating a ship
Destructing enemyship
Destructing ship
Destructing enemyship
Destructing ship
Destructing ship
Destructing Level
Destructing enemyship
Destructing ship
Destructing enemyship
Destructing ship
Destructing enemyship
Destructing ship
Destructing enemyship
Destructing ship
Destructing enemyship
Destructing ship
Destructing enemyship



Here's some code from my ship.h file just for proof:

class Ship
{
public:
...
virtual ~Ship();
...
};



Here is some code from my enemyship.h

class EnemyShip: public Ship
{
public:
...
~EnemyShip();
};



Why are both destructors running? Is there something special I'm supposed to declare my EnemyShip destructor as? Am I supposed to define my ship's destructor as virtual too?

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Booger
Why are both destructors running? Is there something special I'm supposed to declare my EnemyShip destructor as? Am I supposed to define my ship's destructor as virtual too?


Because it's the way it's meant to be: once the derived class has been destructed, the base class is destructed as well. Not only can't you avoid this behavior, you shouldn't try to avoid it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Booger
Ok I understand how the compiler might do the default destructor for my EnemyShip class so I declared the Ship's destructor to be virtual. But it seems both destructors are still occurring.

Here is the output when both destructors have the same code except that the output says "enemyship" on one and "ship" on the other:
*** Source Snippet Removed ***

Here's some code from my ship.h file just for proof:
*** Source Snippet Removed ***

Here is some code from my enemyship.h
*** Source Snippet Removed ***

Why are both destructors running? Is there something special I'm supposed to declare my EnemyShip destructor as? Am I supposed to define my ship's destructor as virtual too?


If the base class destructor is virtual, so are all derived. It's a probably a good practice to specify it also, just to make it clear for a reader.

Since EnemyShip derives from Ship, both destructors are called. First the destructor for EnemyShip, then for Ship.

Share this post


Link to post
Share on other sites
ToohrVyk is right. It is intended for derived classes to call destructors all the way up to the base object. This is a good thing, because you can let, say, the Ship class deal with any allocations it might have made in its destructor and then not worry about cleaning up after ship in each derived class. Can you imagine having to clean up each parent classes allocations? You'd have copy+paste code all over the place.

Consider:
Ship() - cleans up Ship
EnemyShip() - cleans up EnemyShip, Ship
AngryEnemyShip() - cleans up AngryEnemyShip, EnemyShip, Ship


According to your OP, the EnemyShip destructors aren't being called. Your output indicates that they are being [correctly] called.

Quote:
But it seems both destructors are still occurring.

It would seem that you have one of two problems in your code:
1) You believe that there is a problem, but there isn't.
2) You don't want both destructors called, which is in itself a problem because I can't think of a reason why you wouldn't. You might be looking at a design, and not a code problem.

Share this post


Link to post
Share on other sites
So if I didn't declare Ship's destructor as virtual then EnemyShip's destructor would not be called? If that's true then I understand this stuff about virtual.

But onto my errors. I thought that my code was exactly like Amrazek's but only three of my 15 enemy ships' destructor's are called. Why do some of them call and others do not?
A debugger would really come in handy right about now. All I know is that the first two enemyships' destructors run and then I get an error message, and after I click ok on the error box, the third destructor message appears and I get another error box of the same message.

And btw, thank you guys very much for taking so much time out of your lives to help some stupid kid you don't know.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this