Can you put multiple types of classes in the same array?

Started by
19 comments, last by Zukias 10 years, 12 months ago

On and off a couple years; my C++ book that I'd been studying out of was actually lost around the time I got to the polymorphism chapter, so yeah, I'm a bit lacking in this area.

You make a good point about setting the seed at the creation though.

Advertisement

On and off a couple years; my C++ book that I'd been studying out of was actually lost around the time I got to the polymorphism chapter, so yeah, I'm a bit lacking in this area.

You make a good point about setting the seed at the creation though.

Set the seed at game startup and then dont change it, unless you have a specific need for it... which you probably dont.

The simplest solution to what you're trying to do is to have a virtual function that takes in an enum value, the message. Then in the derived class you can switch on that and call the appropriate function to handle it. You can send in a second parameter with a pointer to some data if you want. The simplest way there is to send a void* and case to the right type once you know what the message is. Not great to do in c++, but simple and will solve your problem.

I'm guessing each enemy wants a separate seed so that each enemy does something deterministic independent of the other enemies (so that destroying an enemy won't put the other enemies out of sync due to different numbers of calls to rand() or whatever). That's just a guess though!

I wouldn't recommend having an uber virtual function and a message which you switch with, that kind of defeats polymorphism. If you have an enormous number of messages you need to handle, it gets more attractive, though. And void* isn't good advice either for C++.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

Set the seed at game startup and then dont change it, unless you have a specific need for it... which you probably dont.

When I don't seed the different enemies' RNG values each time they move, they all move in the same directions at each loop iteration. I seed with the index variable so each seed number is different and each of them moves at a different time in a different direction.

I don't know what you mean by number of messages, or even what you mean by messages.

If I set the seed for each of the enemies, I think that would be good for eliminating the need for the second parameter though. This seems like a pretty dead simple solution.

That sounds like you're not using your RNG properly. If you seed it just once at the beginning of the program all the enemies should do different things.

Setting the seed explicitly for each enemy has a use, that is deterministic randomised behaviour for each enemy, but I don't think that is what you are after.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

It's not necessarily a good design idea, but you could add an enum to your base class that determines what derived class to call:

enum EnemySubType
{
  BASE_ENEMY,
  RED_ENEMY,
  BLU_ENEMY,
  GRN_ENEMY
};
 
class ENEMY
{
  protected:
    EnemySubType mySubType;
};

When you need to call your derived class functions that don't exist in the base class:

if(myEnemy.mySubType == RED_ENEMY)
{
  ((RED) myEnemy).myDerivedClassFunction();
}
else if......

If Else statments or Switch Case would work.

I agree that you should potentially redesign your classes/look up polymorphism more, but this could work if you just want to get something running.

You could try a dynamic_cast<RED>, dynamic_cast<BLU>, etc and do work if the resultant pointer is valid.
what

Pretty much a problem of using subclassed objects in a list or whatever type of collection. Realistically the code and the compiler don't know if an object is of a particular subclass unless you cast it to it. Paradigm was basically suggesting you include a virtual copy of the method you're trying to call in the base class so it has a definition to work with, though that only works if every subclass has it. I.e. if each color of enemy overrides move and you're calling move or something.

Ideally if you're going to use a collection like that you only want to use it for iterating purposes, like calling update on groups of objects even if the objects do different things when update is called on them. I'm not really sure what you're trying to accomplish with the AI and seed thing though.

Set the seed at game startup and then dont change it, unless you have a specific need for it... which you probably dont.

When I don't seed the different enemies' RNG values each time they move, they all move in the same directions at each loop iteration. I seed with the index variable so each seed number is different and each of them moves at a different time in a different direction.

I don't know what you mean by number of messages, or even what you mean by messages.

If I set the seed for each of the enemies, I think that would be good for eliminating the need for the second parameter though. This seems like a pretty dead simple solution.

It sounds like you're doing something wrong. If you seed the RNG once at startup, then every number you get after that from the rand() function will be pseudorandom. In other words, any character that uses it to determine their movement should move in a different direction.

Maybe you can include some code so we can see what you're doing.

By "messages" I mean something like this:


enum MESSAGE
{
	MSG_DO_SOMETHING,
	MSG_DO_SOMETHING_ELSE,
};

class ENEMY
{
public:
	virtual void move(void){}
	virtual void handle_message(MESSAGE msg) = 0;
}

class RED : public ENEMY
{
public:
	virtual void move(void);
	virtual void handle_message(MESSAGE msg)
	{
		if(msg == MSG_DO_SOMETHING)
		{
			do_something();
		}
	}
private:
	void do_something(void);
}

class BLUE : public ENEMY
{
public:
	virtual void move(void);
	virtual void handle_message(MESSAGE msg)
	{
		if(msg == MSG_DO_SOMETHING_ELSE)
		{
			do_something_else();
		}
	}
private:
	void do_something_else(void);
}

This method has its problems, but it's also an easy thing to implement if you want to call different functionality in your derived class objects through a pointer to their base class.

When I don't seed the different enemies' RNG values each time they move, they all move in the same directions at each loop iteration. I seed with the index variable so each seed number is different and each of them moves at a different time in a different direction.

Sounds like you're creating each Enemy's PRNG with the same seed. Like some have suggested you could use a since global variable for your PRNG (which is the classic C style), or you could have a PRNG member of your game class and use that to generate a sequence of seeds for each enemy at creation time.

Stephen M. Webb
Professional Free Software Developer

This topic is closed to new replies.

Advertisement