• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

Need some quick C++ help: classes

Status
Not open for further replies.

Ecrofirt

Member
ok, I can't seem to get this erase working.

let's say I'm trying to erase the third item. I've tried the following:

vFireball.erase(3);
vFireball.erase(vFireball[3]);
vFireball.erase(vFireball.at(3));

I'm looking through several guides online for it as well, and they don't seem to be helping.
 

Ecrofirt

Member
ah, I've found the answer in the MSDN.

vFireball.erase(vFireball.begin()+i);

now to wait for the television to become free so i can test the code
 

slayn

needs to show more effort.
I wasn't sure how vector would handle erasing (for all I know it does a constant time erase by swapping for you) but it case it doesn't you could always erase in constant time by doing what you said, swap the element you want to delete to the end first before erasing.

you could just say:

vFireball[3]=vFireball.back();
vFireball.pop_back();


and this would erase the 3rd thing in constant time, assuming vector doesn't resize itself after deletions... which I would think it would only do when it got half empty or some such so that the time used ... I forget word... amortize? In other words the time used isn't as big of a deal. Also note that you don't actually have to 'swap' the two elements. Since you are deleting whats in spot 3 you don't care when the data is lost. So you just copy the last element into spot 3, and then delete out the duplicate of what is now in spot 3 at the end.
 

maharg

idspispopd
vectors never shrink. Technically. (swap an empty one with a used one and you can shrink one deliberately)

Whether you use a vector or a list depends on your needs. If you need to be able to access elements quickly by index (vec) then you'll want to use a vector. In order to improve delete performance, assuming order is not important, you can use the above swap and shrink technique. This is, however, a premature optimization. If you don't care about indexed (random) access, list is probably a better choice since you can insert and remove quickly.

Any decision that affects the clarity of your code negatively should be saved for when you know it's needed. Go the easy to understand way first, then figure out if there is really likely to be a performance benefit to the optimization. Only then should you actually do it.
 

Lathentar

Looking for Pants
Ecrofirt said:
ah, I've found the answer in the MSDN.

vFireball.erase(vFireball.begin()+i);

now to wait for the television to become free so i can test the code
Unit Testing is your friend.
 

Ecrofirt

Member
Until recently all my enemies were exactly the same, so I didn't need to use polymorphism. I was just using a switch to randomly pick which image to use for the enemy.

I've now decided to change up the way my enemies behave, and polymorphism is definitely required. Basically instead of all my enemies moving just left across the screen, I'm going to have some of them home in on my character, and some shoot weapons at him. This is gonig to require an overhaul of the way my enemies function, but I'm not completely familiar with polymorphism in C++. I think I've got it down, but I'd like some confirmation before I rip my code apart and restart everything.

OK, here goes:

I'd do my header file like this:

Code:
class Enemy
{
public:
// Constructors, Destructors
Enemy () {}
virtual ~Enemy() {}

//General methods
virtual void move();
virtual void shoot();

};


then my class files for my enemies would look like this:

Code:
class Rat: public Enemy
{
public:
Rat() {}
~Rat() {}

void move();

};

and now for some vector stuff:
Code:
vector<Enemy> vEnemy;

Enemy NewEnemy;

NewEnemy=new Rat;
vEnemy.push_back(NewEnemy);

Would this work? It looks like it would, but I'd rather have some idea first before I go and start ripping apart the code that I have.

Also, you guys seem to be sugesting to use list<>. I've looked into this, but I can't really see the gain in using it over vector. Can you maybe give a bit more inisght on it?
 

Ecrofirt

Member
ok, so would it look like this:

Code:
vector<Enemy> vEnemy;

Enemy *NewEnemy;

NewEnemy=new Rat;
vEnemy.push_back(NewEnemy);
 

Lathentar

Looking for Pants
More like:

Code:
vector<Enemy*> vEnemy;

vEnemy.push_back( new Rat );

You just need to make sure to call delete when you remove the element.
 

Ecrofirt

Member
so now when I call the vector erase method, I still then have to use a delete to get rid of it? Or do I now not use the erase method or something?
 

Ecrofirt

Member
ok, so say my code looks like this:
Code:
void CreateEnemy(void)
{
Enemy *NewEnemy;
NewEnemy=new Rat;

vEnemies.push_back(NewEnemy);
}


I've got a function that delets the enemy like so:
Code:
void DeleteEnemy(int Number)
{
vEnemies.erase(vEnemies.begin()+Number);
}

how do I go about deleting the newEnemy from the CreateEnemy function? It just seems a bit off to me.
 

slayn

needs to show more effort.
Code:
void DeleteEnemy(int Number)
{
        delete vEnemies[Number];
        vEnemies.erase(vEnemies.begin()+Number);
}
 

Ecrofirt

Member
ok, cool. I had a feeling it was probably something more like that.

Thanks for all the help guys! I'm trying to teach myself this stuff as I go along, so please bear with the dumb questions.
 

Lathentar

Looking for Pants
slayn said:
Code:
#include <cassert>

void DeleteEnemy(int Number)
{
        assert(Number < vEnemies.size && Number >= 0);
 
        delete vEnemies[Number];
        vEnemies.erase(vEnemies.begin()+Number);
}


I added some error checking.
 

maharg

idspispopd
You should really start using iterators directly rather than always working around them. Your code is quite convoluted as is, and indexed lookup is basically specific to the container (two containers do it, vector and deque. The others either don't support it at all (list) or it has a different meaning (map, set)).
 

Ecrofirt

Member
OK, it's a few months later and I've got just about everything working how I'd like with this game. At this point, I'm now trying to make the switch from vectors to lists for my enemies and fireballs to boost my speed a little bit.

I seem to have correctly done the fireball switch, and I can already notice a bit of an increase there. Before there was a bit of a stutter when I'd shoot the first fireball, and it's gone now.

I'm not having as much luck with the enemies, though. I'm running into problems, and I know what the problem is, but I don't know how to fix it.

I'm using polymorphism for my enemies. They're all derived from a base enemy class, and it works perfectly with vectors. Here's how I've got it setup:
Code:
//in my header file
vector<Enemy*> vEnemy;

//in my cpp file, part of my blitting method
void update_gfx()
{
	//this blits the enemies to the screen
        //I'm using SDL, but you should be able to get what I'm doing. the main thing is
        //vEnemy[i]->image
	for(int i=0;i<vEnemy.size();i++) {
		SDL_SetColorKey(vEnemy[i]->image, SDL_SRCCOLORKEY, SDL_MapRGB(vEnemy[i]->image->format, 255, 0, 255));	//set colorkey
		SDL_BlitSurface(vEnemy[i]->image,&vEnemy[i]->r_image,screen,&vEnemy[i]->r_location);
	}

}

And it would work fine. Like I said, I've ported over the fireballs fine, and I'm pretty pisitive it's because they aren't a list of pointers. When I try and change the enemy vector to an enemy list, I'm running into errors. Here's what I've tried to make it look like:

Code:
//in the header file. At the moment it's still vEnemy so I don't have to change letters all around
list<Enemy*> vEnemy;					//out enemy list
list<Enemy*>::iterator	eIter;			//our enemy iterator

//in my blitting method in the cpp file

void update_gfx() {

	//this blits the enemies to the screen
	for(eIter = vEnemy.begin(); eIter!=vEnemy.end(); eIter++) {
		SDL_SetColorKey(eIter->image, SDL_SRCCOLORKEY, SDL_MapRGB(eIter->image->format, 255, 0, 255));	//set colorkey
		SDL_BlitSurface(eIter->image,&eIter->r_image,screen,&eIter->r_location);
	}

}

OK, with the way I'm doing it now, I'm getting a bunch of errors with the ->image. This doesn't happen unless I make it a list of pointers, which is why I'm pretty sure it's because it's a list of pointers. Here are a few of the errors I'm getting:

error C2839: invalid return type 'std::list<_Ty>::_Tptr' for overloaded 'operator ->'
with
[
_Ty=Enemy *
]


error C2227: left of '->image' must point to class/struct/union

If i change it to list<Enemy> vEnemy I don't get these errors. The problem is, when I create my enemies, they don't become their specific type like they should. They all just become a generic enemy, and do nothing. Here's the code for that section when I don't have this set up as a list of pointers to enemies:

Code:
void generate_enemy() {
			Enemy *NewEnemy;		//this creates a new enemy.
			
			//this chooses a random number based on the current level.
			//It then creates an enemy based on that number, and puts 
			//it into the enemy vector.
			switch (rand()%4) {
				case 0:
					NewEnemy=new Pig(level);
					break;
				case 1:
					NewEnemy=new Skeleton(level);
					break;
				case 2:
					NewEnemy=new Zombie(level);
					break;
				case 3:
					NewEnemy=new Goblin(level);
					break;
			}

                        //this pushes the enemy back
                        /*this it the only way it'll work. This isn' t how I had it for the vectors. 
For the vectors, it was  vEnemy.push_back(NewEnemy); but with lists I'm getting this error:

error C2664: 'std::list<_Ty>::push_back' : cannot convert parameter 1 from 'ENEMY *' to 'const ENEMY &'
        with
        [
            _Ty=ENEMY
        ]
        Reason: cannot convert from 'ENEMY *' to 'const ENEMY'
        No constructor could take the source type, or constructor overload resolution was ambiguous */
			vEnemy.push_back(*NewEnemy);							

}

I'm at an impass here. I don't know how to get rid of the -> errors if I make it a list of pointers, and if I don't make it a list of pointers, I can't have specific enemies.

Can someone help point me where I need to go?
 

Ecrofirt

Member
Cerebral Palsy said:
Classes suck balls. I took my first c++ class a few semesters ago, and had a horrible time learning them.

I didn't understand them AT ALL when I first learned them. Of course, that was probably because my teacher had no idea what she was teaching.

When I had to learn them for Java, everything clicked immedietly, and I was actually drawing from my C++ non-experience. Having a better teacher was a miracle. They're very easy to make and work with once you know what you're doing.
 

Lathentar

Looking for Pants
Uhhh... for your iterator...

(*eIter)->image.

Done, eIter is an iterator. *eIter returns what its pointing at, which is a Enemy*, then with your Enemy* you can access the image using the -> operator.
 

Ecrofirt

Member
Yep, I had actually figured this out awhile ago, but I thought I hadn't.

It actually needs to be (*eIter).image, or I get an error. It was this error that was making me this wasn't working.

I'm now running into a problem with my generate enemy function. It generates an enemy, but they're all generic enemies. It's like the polymorphism isn't working.

Thanks for the help Lathentar!
 

Lathentar

Looking for Pants
You should repost the updated code to the generate_enemy function with all the other code segments needed.
 

Ecrofirt

Member
Code:
//this is in the header file
list<ENEMY> vEnemy;					//out enemy list
list<ENEMY>::iterator	eIter;			//our enemy iterator

Code:
void generate_enemy() {
			ENEMY *NewEnemy;			//this creates a new enemy
			
			//this chooses a random number based on the current level.
			//It then creates an enemy based on that number, and puts 
			//it into the enemy vector.
			switch (rand()%4) {
				case 0:
					NewEnemy=new Pig(level);
					break;
				case 1:
					NewEnemy=new Skeleton(level);
					break;
				case 2:
					NewEnemy=new Zombie(level);
					break;
				case 3:
					NewEnemy=new Goblin(level);
					break;
			}

			vEnemy.push_back(NewEnemy);	//this pushes the enemy back
}
 

Ecrofirt

Member
OK, I may have this all figured out except for one more small error I'm running into now.

Code:
SDL_BlitSurface((*eIter)->image,&eIter->r_image,screen,&eIter->r_location);

is giving me

error C2839: invalid return type 'std::list<_Ty>::_Tptr' for overloaded 'operator ->'
with
[
_Ty=ENEMY *
]


error C2227: left of '->r_image' must point to class/struct/union
type is 'std::list<_Ty>::_Tptr'
with
[
_Ty=ENEMY *
]

and another sed of those for &eIter->r_location

Basically everything is working now, but the &'s are throwing everything off, and SDL_BlitSurface needs them or it throws an error.
 
Status
Not open for further replies.
Top Bottom