Sign in to follow this  

Possible to have Structs with Derived Classes of a Class in it?

This topic is 2546 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

In order to make everyone understand my question, I'll give an example:

Pokemon! Here we have the classes of Pokemon.


class Pokemon
{
protected:
int HP;
int XP;
std::string Name;
std::string Type;
public:
virtual void Set(int, int, std::string, std::string);
virtual void Get(int);
};

class Pikachu : public Pokemon
{
public:
void Set(int HP, int XP, std::string Name, std::string Type);
void Get(int);
};

class Togepi
{
public:
void Set(int HP, int XP, std::string Name, std::string Type);
void Get(int);
};

void Pikachu::Set(int HP, int XP, std::string Name, std::string Type)
{
Pikachu::HP = HP;
Pikachu::XP = XP;
Pikachu::Name = "Pikachu";
Pikachu::Type = "Electric";
}

void Togepi::Set(int HP, int XP, std::string Name, std::string Type)
{
Togepi::HP = HP * 2;
Togepi::XP = XP / 2;
Togepi::Name = "MY AWESOME KIDDO"
Togepi::Type = "Normal";
}

void Pikachu::Get(int position)
{
switch(position)
{
case 1:
std::cout << Pikachu::HP;
break;
case 2:
std::cout << Pikachu::XP;
break;
case 3:
std::cout << Pikachu::Name;
break;
case 4:
std::cout << Pikachu::Type;
break;
}
}

void Togepi::Get(int position)
{
switch(position)
{
case 1:
std::cout << Togepi::HP;
break;
case 2:
std::cout << Togepi::XP;
break;
case 3:
std::cout << Togepi::Name;
break;
case 4:
std::cout << Togepi::Type;
break;
}
}



And now I want to have a struct that contains a generic Pokemon class, with by using templates, I can change the class typename to different classes as I pleased...


template <typename T>
struct GenericPKMN
{
std::string AdditionalInfo;
int NumberofPKMN;
T Generic;
};

int main()
{
GenericPKMN MyPikachu;
MyPikachu.AdditionalInfo = "Testing my Pikachu...";
MyPikachu.NumberofPKMN = 1;
//OH NO!!
return 0;
}



What should I put at the comment line? What else can I change to make my structs able to polymorph to different derived classes of a particular class?

Thanks in advance.

Share this post


Link to post
Share on other sites
I don't see why you would want to use a distinct class per Pokemon, especially not after what you've shown so far. It's probably much better to use the Prototype pattern (having a template instance and cloning it - e.g. you'd have one Pokemon instance for each Pokemon type, and if you want a Pikachu, you'd clone the Pikachu instance).

An alternative would be to use the Flyweight pattern (each Pokemon has a reference to a PokemonType instance - the Pokemon object would hold data such as position, XP and current HP while the PokemonType object would hold shared data such as type, name and max HP).


As for templates, when creating an instance of your templated struct, you do have to specify what type you're using it with. For example, take std::vector: you have to specify what it will hold beforehand (std::vector<std::string> names). Templates generate code at compile-time based on what types you've used them with. I'm don't think that's really what you need here though.

Having that said, what exactly are you trying to achieve here? Can you give a high-level explanation (i.e. what's the purpose of all this code)?

Share this post


Link to post
Share on other sites
I thought I was clear enough; Apparently not...

My only purpose is to make a polymorphable struct variable that I can use for easy-to-handle switching Pokemon, calling Pokemon member functions, battling, and easy manipulation of not moving my codes around too many times.

I'm using my Pokemon to get randomly picked, and face-off in a 1 vs 1 battle.
Under random circumstances, Pokemon 1 will attack Pokemon 2, or it could be vice versa, or it could be that the attack missed.

There's about 10 Pokemon I have to make, and they have to contain a lot more information than the ones I posted up there...(Stats, Attack, Defense, Sp. Defense, Sp. Attack, Gender Ratio, Attack Ratio, etc...) and all of the info are not entirely the same among the same species (Pikachu 1 isn't the same as Pikachu 2).

And I thought, maybe I can create a struct variable that can hold 1 Pokemon of a generic type, generic species, generic HP and all that, and do the same for the other Pokemon.

Once that is done, I can just call on either struct variable and do the actions necessary to complete the battle.

I'm currently doing a homework that wants me to design and show the battle outcome of 2 Pokemons (same or different, doesn't matter). I decided to amp up the difficulty, and I'm now implementing SDL into that. (The difficulty was normal to mid-difficult, now it's really difficult! XD)

I'm just stuck on polymorphing structs, and inheritable classes template changing...if that exists...

I'm also thinking of Pointers/Dynamic Memory method, so that whenever I call on Pokemon 1 with a specified Pokemon species, I will be able to modify what was inside the field, and do the neccessary actions.

I haven't heard of Flyweight Method...(And yes, Google reveals that it's Flyweight Pattern), so I'm not familar with it. Is it really possible that I can pinpoint my pointers to specific class member fields and whenever I want my Pokemon to do something, I change the values pointed by my pointers? Should I mix it in with dynamic memory management?

The basis of my struct class: (pseudo-code)

struct Pokemon
{
*Image; //This is used for pointing to a specific sprite.
*PKMN; //This is to point to a (class? struct?) that I can use to
//create the Pokemon with.
*CurrentHP //Pointer to an integer that I can modify.
*CurrentXP //Pointer to an integer that I can modify.
*TargetPKMN //Pointer to a Pokemon this Pokemon is attacking.
*Stats //The current status this Pokemon has.
};




I'm not sure if this is detailed enough. Thanks in advance.

Share this post


Link to post
Share on other sites
So, there's Pokemon types - Pikachu, whatever - and there's actual Pokemons (my Pikachu, your Pikachu). Pokemons of the same type may vary a bit in stats, but in the end you can treat all of them the same - that is, all Pokemon can be given, for example, move and attack orders, and all of them have the same kind of stats, right?

Prototype should work fine here - you'll want to customize it a bit to take the stat variations in mind (you may want to store specific variation information somewhere, and take it into account when copying a prototype instance).

If some Pokemon have radically different behavior, then (run-time) polymorphism may come in handy. Basically, you have a class (Pokemon) with virtual functions (applyDamage, move, attack). Pokemons (Pikachu) with different behavior can inherit from this base class, and provide their own implementations for these virtual functions (Pikachu could provide a custom applyDamage function). When you have a pointer-to-a-Pokemon and you call applyDamage on it, then if the actual object you're pointing to is a Pikachu, the Pikachu version of applyDamage will be called instead of the Pokemon version. So, regardless of the actual type of the object you're working with, you can still treat it as a generic Pokemon.

However, most differences can likely be modeled with some additional variables, so don't think you have to create a different class for each Pokemon type. It's an option, but not the only one. For example, in a strategy game an artillery unit can be implemented by adding a minimum and maximum range to the Unit class, instead of creating an ArtilleryUnit class.


I would not create a struct that holds pointers to member variables of another object. At most it should hold a pointer to that object. Giving away pointers to internal data is a bad idea. It'll make it very difficult to enforce constraints, such as limiting HP between 0 and the maximum HP for that Pokemon. If you have a pointer to that HP variable, you can set it to anything you want. If you only have a pointer or reference to the Pokemon object it belongs to, you can call an applyDamage() function and you can be certain the Pokemon is not left with an invalid HP value. Additionally, that function could inform the Pokemon's owner if the damage causes the Pokemon to die, or anything else that should happen. So, don't expose such variables directly. Work through an objects interface instead.


Oh, note that, in C++, classes and structs are pretty much the same (the differences have to do with default access and inheritance levels, private and public respectively). Also note that, when a class has a virtual function, it's destructor should also be marked as virtual. Finally, templates do provide some sort of polymorphism, but only at compile-time. Useful when you know what types you'll be working with but you don't want to write the same code for multiple types.

Share this post


Link to post
Share on other sites

This topic is 2546 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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