I know enums have been spoken about in many threads. I am hoping to not only learn from these threads but also consolidate them into one thread. this way not only will my questions be answered, but anyone visiting this forum will have one very comprehensive thread that talks about the "enum" keyword in C++.
For those of you who don't know me, which is pretty much everyone here, I received a degree in Game Development from Full Sail University. AS much as I learned from this school, I have yet to develop my own programming philosophy. Furthermore, I love writing code for two main reasons. One, I enjoy it. Secondly, I believe my programs and the programs I work on benefit those whom use it. So, I may talk about htings from the user perspective, because the better we do to serve the user, the more successful are our programs. Bottom line is, I don't know how much impact polymorphic code has on the efficiency of a program. Granted, this can be easily solved by taking time stamps on programs and how they go about accomplishing the same thing.
The example I wish to explore in this thread is not just enum philosophy its application in a solution I wish to write. This example is a Tarot Card layout analyzer. If the user uses this software, they will let the program know the cards in a reading. Then the analyzer will analyze the reading and give helpful hints on what the cards may be saying. If the solution uses enums, then the cards value, and their suit will be an enumeration. The alternative is having a card class. There are five types of cards, which inherit from the card class,: Wands, Swords, Pentacles, Cups, and Major Arcana. If I were to use polymorphism, then it is somewhat easier to add in other suits at a later date. Otherwise, it probably makes more sense to have an enumeration for the suits, because I already know the suits. If you were me, which would you use for the suits? How would your choice affect the efficiency of the software and the amount of time it takes to implement a solution?
I hope in helping me solve and develope this philosophy, we will all benefit. Sorry for rehashing this subject.
The correct way to model this is for a card to be an arbitrary value (a number, a string, or an enum), and for the properties of a card (e.g. suit, name string, etc.) to be computed by a function.
For example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
enumclass Suit{
Spades = 0,
Diamonds,
Clubs,
Hearts,
};
int build_card(Suit s, int value){
return (int)s + value * 4;
}
Suit get_suit(int card){
return (Suit)(card % 4);
}
int get_value(int card){
return card / 4;
}
The suit should preferably not be explicitly stored by a card object. It's information that can be derived from the identity of the card.
it feels to me like you do want a card class. you need to store the text to present to the user somewhere anyway, and that is tied to the individual cards, and you also have to deal with the order of the cards / position in input to select text based off previous cards shown. If you do it with the minimal enum approach you can define the deck, but then you need a whole slew of side-code to solve the rest of the problem in your game. Put it all into one class feels better to me?
I agree the above is an awesome way to deal with just the deck, just that your problem probably needs more than just a deck due to the nature of the problem you are solving.
I was overthinking this example. It does not make sense to have a card class and have children classes based on the suit type. You are right, the card only ought to store its value. Based on its value, the program can calculate its suit. Not the best example of when to use an enum versus having a parent and child(ren) classes.
Something else, I wish to address in this thread are a couple of things I read (but have yet to test). First, doing an if check to find out what type of pointer is an expensive if check. For example, if there is an array of GameObjects and in this array are coins, blocks, koopas, goombas, and other objects, then it may make sense to check to see if an object is a coin versus a block. The if check is performance prohibitive. Is this a myth waiting to be busted, or is there truth in this?
The second rumor is one I read in a book. This is that it is a bad idea to have GameObjects stored in an array, because one GameObject, like a coin, probably is smaller than a goomba. Therefore, iterating through the array of different sized GameObjects is an accident waiting to happen. Despite reading this book and understanding what the author is saying, I am pretty sure Games have arrays of different sized objects, and somehow get away with coding in this manner. If both of the myths are myths, then from a efficiency standpoint, it really does not matter if the tarot card program has one card class with a value and 5 classes (one for each suit) inherits from this class. This way getting the suit avoids the run time cost of dividing the value by 5.
is an array of GameObjects and in this array are coins, blocks, koopas, goombas, and other objects, then it may make sense to check to see if an object is a coin versus a block. The if check is performance prohibitive. Is this a myth waiting to be busted, or is there truth in this?
dynamic_cast, which is used to check if an object is an instance of a class, is usually slow.
There are ways to avoid dynamic_casting, but it's usually better to just design the code so you don't need to branch based on RTTI, by using polymorphism.
This is that it is a bad idea to have GameObjects stored in an array, because one GameObject, like a coin, probably is smaller than a goomba. Therefore, iterating through the array of different sized GameObjects is an accident waiting to happen.
I don't know what "an accident waiting to happen" means. OOP is generally discouraged in modern game programming because it's usually less cache-friendly than data-oriented programming. Polymorphism requires pointers, which require jumping around in memory to traverse a data structure.
This way getting the suit avoids the run time cost of dividing the value by 5.
if statements cost you, yes. It depends on a lot of things how much... modern cpu can do branch prediction and reduce the costs but they can only do so much of that (even 3 or 4 nested if statements can't be predicted its too much for the hardware as I understand it). You can avoid if statements in some code. consider
double answer[2] = {3.14,2.718};
if(input == 'p')
result = answer[0];
else result = answer[1];
can be rewritten as
result = answer[input != 'p']; //if its p, condition is false, which is zero, first entry in array. else second value.
this is just one example that has nothing to do with classes.
the gains are going to be tiny unless you are doing a whole bunch of something, talking millions+. If you get into the billions, you begin to actually save fractions of seconds that can be measured. Is it worth it?