Thread: Constructive criticism highly appreciated!

  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    20

    Post Constructive criticism highly appreciated!

    I have previously had some questions about classes and references/pointers on this forum. And - I got some good answers, mainly from major_small and Dae. Thanks to both of you!

    Now, as it often is with answers, they mainly made me realize that there is a lot more I need to know.

    My plan is to make an ASCII text game, featuring a Wild West theme, and a simple set of pen and paper RPG-style rules - WITH A TWIST!

    I want to make it completely OOP. That means, I want to make easily reusable, adjustable, expandable, and portable code.
    I want to make lots of little units (classes) of code that is able communicate and exchange information with eachother.
    That is what I imagine real OOP is. Am I wrong?

    I realize many programmers might think that it would be a waste of time, putting that much effort into a fairly simple ASCII game. But I don't care about that. For me, the object is not to make a game quickly, but to learn how to do C++ OOP, and have fun at the same time!

    I have done some noob level programming in different languages from time to time, but C++ and espacially C++ classes and the OOP concept are very new to me. So what i'd really be grateful for, is any constructive criticism anyone can give me on style of code, consistency, variable/function/method naming, coment style, anything you can think of, on the following piece of code. I have comented on nearly everything, to try and demonstrate the limits of my knowledge.

    Oh, and I relize that this is a HUGE post that represents A LOT of questions, but please bear with me, as i have never before had the opportunity to have a seasoned or, in fact, any programmer look at any of my code. And I really want to get this exactly right.

    Code:
    // Draw! -The name of the game.
    
    
    #include <stdlib.h>          // This is where header files are included. I must admit
    #include <iostream.h>        // that I don't know much about it, except they let me
    #include <time.h>            // access certain functions, that would otherwise be
    #include <conio.h>           // unavailable.
    #include <string>
    
    
    class human  // Class declaration. A class is just a definition that can be used
    {            // to create an object.
    	
    	int health, gunSkill;			// These variables have the default
    	string firstName, lastName, alias;      // protection level of Protected.
    						// Protected variables and methods can
    						// be accessed from anywhere inside the
    						// object, but not from outside.
    	
    	public:	// Everything below this is public, meaning it can be accessed from
    		// outside of the object to be.
    	
    	int dice[10];	// The program won't compile with this array protected. Why?
    			// The constructor uses this variable, so is it because the
    			// constructor creates the object, and is therefore not
    			// really a part of it as such?
    	
    	human()	// This constructor lets me set default values for all the variables,
    	{	// and call methods, whenever a new object is created.
    		
    		dice[0] = 0;
    	}
    	
    	// I have decided not to include a destructor,
    	// because I read on the C Board, that c++ provides
    	// me with a default destructor.
    	
    	int rollDice(int numberOfDice, int sides)	// This is a method of the class.
    	{						// It rolls up to 9 virtual dice
    		int result=0;			        // with x number of sides, puts
    							// the results in dice[], and
    		if (numberOfDice>9)		        // returns the total.
    		{					// The two if statements protects
    			numberOfDice=9;			// the method from numberOfDice
    		}					// being set too high, and devide
    							// by zero errors (from sides
    		if (sides>0)				// arguement being set to 0).
    		{
    			for (int x=0; x<numberOfDice; x++)
    			{
    				dice[x] = (rand()%sides)+1;
    				result = result + dice[x];
    			}
    		}
    			// This is my primitive way of returning an error message. That should probably
    		else	// be handled by a sepparate class, but I don't know anything about that yet.
    		{
    			cout << endl << "Error! player.rollDice() arguement out of range.";
    		}
    		
    		return result;
    	}
    	
            // I am not sure weather the following methods are desirable, or if I should
            // simply make those variables public.
    	int getHealth()
    	{		
    		return health;
    	}
    	
    	void setHealth(int newHealth)
    	{
    		health = newHealth;
    	}
    	
    	int getGunSkill()
    	{
    		return gunSkill;
    	}
    	
    	void setGunSkill(int newGunSkill)
    	{
    		gunSkill = newGunSkill;
    	}
    	
    };
    
    class player : public human	// Another class declaration. This one extends on previous class "human",
    {			        // meaning it inherits all its variables and methods, except those that
    			        // have private protection level.
    	public:
    	
    	player()		// Now the constructor calls a method.
    	{			// The code in the parent contructor is still carried out.
    		gameStart();
    	}
    	
    	~player()		// This time I have chosen to include a destructor, because I want to run a method
    	{			// to inform the user, whenever a player object is destroyed.
    		gameOver();
    	}
    	
    	
    	int rollDice(int numberOfDice, int sides)	// Since this method has the same name as one in its
    	{						// parent class, this one will simply overwrite the
    							// parent version.
    		int result=0;
    		cout << endl << "Please press a key to roll " << numberOfDice << "D" << sides << "!" << endl;
    		
    		getche();	// The getche() function checks the keyboard buffer, and returns its contents when
    				// someting is pushed into it. Since I am not assigning that value to a variable,
    				// it simply disappears into oblivion. However, I am not too happy with it, since
    				// it seems to have the undesirable ability to produce wierd errors.
    		
    		if (numberOfDice>9)
    		{
    			numberOfDice=9;
    		}
    		
    		if (sides>0)
    		{
    			for (int x=0; x<numberOfDice; x++)
    			{
    				dice[x] = (rand()%sides)+1;
    				result = result + dice[x];
    			}
    		}
    		
    		else
    		{
    			cout << endl << "Error! player.rollDice() arguement out of range.";
    		}
    		
    		dice[numberOfDice]=0;
    		
    		return result;
    	}
    	
    	void sayDice()	// Gives a player object the ability to print its last die roll to the screen.
    	{
    		
    		if (dice[0]!=0)
    		{
    			cout << endl << "Dice 1: " << dice[0];
    			for (int x=1; dice[x]; x++)
    			{
    				cout << " Dice " << x+1 << ": " << dice[x];
    			}
    			cout << "." << endl;
    		}
    		else
    		{
    			cout << endl
    			<< "Error! player.sayDice(): No dice were rolled." << endl
    			<< "content of the array is:";
    			
    			for (int x=0; x<10; x++)
    			{
    				cout << endl << "Cell [" << x << "]: " << dice[x];
    			}
    
    		}
    	}
    	
    	// The last two methods (that are called in the constructer and destructor) could contain
    	// something like a character generation- and game over sequence. Or perhaps such things
    	// should be kept in a separate "game" class, along with the rest of the game flow?
    	void gameStart()
    	{
    		cout << endl << "There is a new sherrif in town";
    	}
    	
    	void gameOver()
    	{
    		
    		cout << endl << endl << "Game Over." << endl << "Press a key to exit";
    		getche();
    	}
    };
    
    int main()
    {
    	
    	srand(time(0));        	// The srand() function is used together with the time() function to seed
    				// the rand() function, so it will produce a different set of pseudo-random
    				// numbers for each run. They are not really random, as they are picked from
    				// a (very long) list, but "random" enough for the player not to recognize.
    	
    	player playerObject; // Here an object called "playerObject" is created from the player class.
    	
    	cout << endl
    	<< "You now have the profound opportunity to roll 3 virtual 6 sided dice." << endl
    	<< "Be careful in performing this dire task, as the result will determine your starting healt!";
    	playerObject.setHealth(playerObject.rollDice(3, 6));
    	playerObject.sayDice();
    	
    	cout << endl << "That makes your current health " << playerObject.getHealth() << ".";
    	
    	// I could destroy the object here, to free the memory
    	// it exists in, like this:
    	// ~playerObject();
    	// However, I am not going to, since c++ does that
    	// automatically when the main() function returns 0.
    	
    	
    	return 0;
    }
    As you can see, there are some questions in there about how to structure my program. I imagine something like a "game" class to run everyting during the game, and a "system" class to handle system specific calls, to make it easier to port later. But I really could use a good wiev of what classes would generally be needed for a game, what they would do, and how they might interact.

    I welcome answers from anyone, be it the noober- or the über-programmer!

    Thank you in advance

  2. #2
    The N00b That Owns You!
    Join Date
    Jul 2005
    Location
    Canada!
    Posts
    178
    WOW! lol i dont know how id make it all oop i suck at oop but understand it good on ya

    Sincerly noober-
    New Function!!!!

    glAddIdol(C+noob);

    The feeling of rusty spoons against my salad fingers is almost ORGASMIC

  3. #3
    The N00b That Owns You!
    Join Date
    Jul 2005
    Location
    Canada!
    Posts
    178
    // I have decided not to include a destructor,
    // because I read on the C Board, that c++ provides
    // me with a default destructor.
    i know enough to still provide a destructer because sometimes its a good hbit to make

    ex.
    static constructor();
    virtual ~constructor();
    New Function!!!!

    glAddIdol(C+noob);

    The feeling of rusty spoons against my salad fingers is almost ORGASMIC

  4. #4
    Registered User major_small's Avatar
    Join Date
    May 2003
    Posts
    2,787
    as for your logic/etc., I haven't taken too much of a look at it, but I did find this spelling error (you missed the last 'h' on health):
    Code:
    	cout << endl
    	<< "You now have the profound opportunity to roll 3 virtual 6 sided dice." << endl
    	<< "Be careful in performing this dire task, as the result will determine your starting healt!";
    	playerObject.setHealth(playerObject.rollDice(3, 6));
    	playerObject.sayDice();
    Join is in our Unofficial Cprog IRC channel
    Server: irc.phoenixradio.org
    Channel: #Tech


    Team Cprog Folding@Home: Team #43476
    Download it Here
    Detailed Stats Here
    More Detailed Stats
    52 Members so far, are YOU a member?
    Current team score: 1223226 (ranked 374 of 45152)

    The CBoard team is doing better than 99.16% of the other teams
    Top 5 Members: Xterria(518175), pianorain(118517), Bennet(64957), JaWiB(55610), alphaoide(44374)

    Last Updated on: Wed, 30 Aug, 2006 @ 2:30 PM EDT

  5. #5
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Not a bad start...


    Well first since you are making the player class derived from the human class, you should make a deconstructor in the player class, and set it to virtual: virtual ~human() {}. Also.. the compiler does set a default constructor and deconstructor, but neither do anything, so dont expect the default deconstructor to pick up after you.

    I'm not going to look over the actual coding of how you made the dice roll, or why you are setting dice[numberOfDice]=0; at the end of the function, and just concentrate on OOP concept.

    OOP is Object Oriented, so thats the working with objects, not the 'doing everything in the game inside of objects (classes)'. Your start game and end game functions would make more sense outside of the player class, why not to because 1) its a bit pointlessly confusing, and 2) the object of the player larger in data, which may not be good in theory if you make more objects of player.

    In your function: int rollDice(int numberOfDice, int sides), I believe you meant to do: if (numberOfDice>9), before you cout, since the cout would say like 16, then your if statement brings it down to 9 after saying 16, should bring it down to 9 then say 9.

    Why are you using getche(); if you dont like it then? If you have not taken in data using cin <<, then you can simply use cin.get(); to pause. But if you have taken in data using cin <<, when you want to pause use:
    cin.ignore();
    cin.get();

    You're using some headers that may become deprecated in the future, because they are meant for C, not C++. <iostream.h> should be <iostream>, and you forgot the line: using namespace std;. I'm not sure but I think <stdlib.h> should be <cstdlib>, and I'm not sure about the rest. Headers without .h are meant for C++, headers with .h are meant for C or C++, as some .h's dont have no-extension versions.

    Generally coding style is to capitalize class names.. and if the function inside of a class is as long as yours are, to seperate it from the class, then use the syntax: type class name::function name (), below the class. Doing this you can seperate the class body and put it in a .h, then #include it into a .cpp where you have the functions using that syntax.

    Code:
    ////////////////// main.h
    
    class human  // Class declaration. A class is just a definition that can be used
    {            // to create an object.
    	
    	int health, gunSkill;			// These variables have the default
    	string firstName, lastName, alias;      // protection level of Protected.
    						// Protected variables and methods can
    						// be accessed from anywhere inside the
    						// object, but not from outside.
    	
    	public:	// Everything below this is public, meaning it can be accessed from
    		// outside of the object to be.
    	
    	int dice[10];	// The program won't compile with this array protected. Why?
    			// The constructor uses this variable, so is it because the
    			// constructor creates the object, and is therefore not
    			// really a part of it as such?
    	
    	human()	// This constructor lets me set default values for all the variables,
    	{	// and call methods, whenever a new object is created.
    		
    		dice[0] = 0;
    	}
    	
    	// I have decided not to include a destructor,
    	// because I read on the C Board, that c++ provides
    	// me with a default destructor.
    	
    	int rollDice(int numberOfDice, int sides);
    	
            // I am not sure weather the following methods are desirable, or if I should
            // simply make those variables public.
    	int getHealth()
    	{		
    		return health;
    	}
    	
    	void setHealth(int newHealth)
    	{
    		health = newHealth;
    	}
    	
    	int getGunSkill()
    	{
    		return gunSkill;
    	}
    	
    	void setGunSkill(int newGunSkill)
    	{
    		gunSkill = newGunSkill;
    	}
    	
    };
    
    class player : public human	// Another class declaration. This one extends on previous class "human",
    {			        // meaning it inherits all its variables and methods, except those that
    			        // have private protection level.
    	public:
    	
    	player()		// Now the constructor calls a method.
    	{			// The code in the parent contructor is still carried out.
    		gameStart();
    	}
    	
    	~player()		// This time I have chosen to include a destructor, because I want to run a method
    	{			// to inform the user, whenever a player object is destroyed.
    		gameOver();
    	}
    	
    	
    	int rollDice(int numberOfDice, int sides);
    	
    	void sayDice();
    	
    	// The last two methods (that are called in the constructer and destructor) could contain
    	// something like a character generation- and game over sequence. Or perhaps such things
    	// should be kept in a separate "game" class, along with the rest of the game flow?
    	void gameStart()
    	{
    		cout << endl << "There is a new sherrif in town";
    	}
    	
    	void gameOver()
    	{
    		
    		cout << endl << endl << "Game Over." << endl << "Press a key to exit";
    		getche();
    	}
    };
    
    ///////////////main.cpp
    #include "main.h" //where we get the class from
    #include <iostream>
    #include etc. etc.
    
    int human::rollDice(int numberOfDice, int sides)	// This is a method of the class.
    	{						// It rolls up to 9 virtual dice
    		int result=0;			        // with x number of sides, puts
    							// the results in dice[], and
    		if (numberOfDice>9)		        // returns the total.
    		{					// The two if statements protects
    			numberOfDice=9;			// the method from numberOfDice
    		}					// being set too high, and devide
    							// by zero errors (from sides
    		if (sides>0)				// arguement being set to 0).
    		{
    			for (int x=0; x<numberOfDice; x++)
    			{
    				dice[x] = (rand()%sides)+1;
    				result = result + dice[x];
    			}
    		}
    			// This is my primitive way of returning an error message. That should probably
    		else	// be handled by a sepparate class, but I don't know anything about that yet.
    		{
    			cout << endl << "Error! player.rollDice() arguement out of range.";
    		}
    		
    		return result;
    	}
    
    void player::sayDice()	// Gives a player object the ability to print its last die roll to the screen.
    	{
    		
    		if (dice[0]!=0)
    		{
    			cout << endl << "Dice 1: " << dice[0];
    			for (int x=1; dice[x]; x++)
    			{
    				cout << " Dice " << x+1 << ": " << dice[x];
    			}
    			cout << "." << endl;
    		}
    		else
    		{
    			cout << endl
    			<< "Error! player.sayDice(): No dice were rolled." << endl
    			<< "content of the array is:";
    			
    			for (int x=0; x<10; x++)
    			{
    				cout << endl << "Cell [" << x << "]: " << dice[x];
    			}
    
    		}
    	}
    
    int player::rollDice(int numberOfDice, int sides)	// Since this method has the same name as one in its
    	{						// parent class, this one will simply overwrite the
    							// parent version.
    		int result=0;
    		cout << endl << "Please press a key to roll " << numberOfDice << "D" << sides << "!" << endl;
    		
    		getche();	// The getche() function checks the keyboard buffer, and returns its contents when
    				// someting is pushed into it. Since I am not assigning that value to a variable,
    				// it simply disappears into oblivion. However, I am not too happy with it, since
    				// it seems to have the undesirable ability to produce wierd errors.
    		
    		if (numberOfDice>9)
    		{
    			numberOfDice=9;
    		}
    		
    		if (sides>0)
    		{
    			for (int x=0; x<numberOfDice; x++)
    			{
    				dice[x] = (rand()%sides)+1;
    				result = result + dice[x];
    			}
    		}
    		
    		else
    		{
    			cout << endl << "Error! player.rollDice() arguement out of range.";
    		}
    		
    		dice[numberOfDice]=0;
    		
    		return result;
    	}
    
    //you could seperate those gamestart, gameover, etc. method and put them here, and prototype them up there (or in the .h file).
    
    int main()
    {
    //etc.
    }
    It should let you make dice[10] private.. odd, and setting dice[0] = 0; is only setting the first value of the array to 0, not sure what that accomplishes since you overwrite it later, might as well disclude that.

    Oh and its not exactly player.rollDice(), its player::rollDice().. thinking about it that way will help.

    Last note.. it seems like you are trying too hard to make use and example using OOP. Put methods that make sense in with classes that make sense, you probably shouldnt just throw in your dice method into the human class just because you're dying to throw something into it. If you're just using it as an example of how to override methods of base classes, alright cool.. but otherwise the player class would usually contain health, stats, what to do when taking damage, etc. and not gamestart, gameover, rolldice.

    Also when coding try it make it readable, which falls under 1) splitting up the class from the long methods, and seperating them into the files, 2) good tabbing/spacing, which you do have, 3) good, consistant coding style, well yours is half way there. I would recommend using a common coding style for all of your code, but that may be a little bit to take in right now, if not I'll paste it, its about naming your variables, classes, objects, and functions, I've noticed it in code, and read it in books.
    Last edited by Dae; 07-14-2005 at 03:31 AM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    and setting dice[0] = 0; is only setting the first value of the array to 0, not sure what that accomplishes since you overwrite it later, might as well disclude that.
    Any elements of an array which you do not initialize, provided you have initialized at leats one of them, will be set to zero. Thus:
    Code:
    int foo[ BAR ] = {0};
    Initializes all elements to zero. However, don't be confused with the initialization. This:
    Code:
    int foo[ BAR ] = {1};
    Sets the first element to 1 and all remaining elements to 0. It doesn't set them all to 1.


    Quzah.
    Last edited by quzah; 07-14-2005 at 03:39 AM. Reason: Added quoted text.
    Hope is the first step on the road to disappointment.

  7. #7
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Oh, and about the "easily reusable, adjustable, expandable, and portable code" part. You know how a function accomplishes one goal, whether its adding two values, or printing the contents of an array, that is how you should think about classes. The difference between a function accomplishing a goal, and a class, is a class is used when you accomplish say 5 goals to one thing. For example:

    A linked list would have a feature to add/delete, go to next, go to prev, print contents of the linked list, etc. You would make a function to accomplish the add part, a function for the delete part, etc. and since all of these revolve around 1 linked list, you would be better off putting it all in one class, but only what relates to modifying that linked list.

    Another, better, example: a class that lets you set the value of an array (thats inside the class), and have a function that allows you to resize the array, and one to print the array, and one to insert a value into the array (which relies on resizing it of course). You could of course have these functions outside seperately, but in a class they belong because it groups them and simplifies the syntax. Also of course that lets you do operator overloading so you can treat the object as if it was an array, but dont worry about that now.

    Anyway, the point is your classes, and functions should be as stand-alone as possible. Meaning your classes should be less knotted, and able to resuse them for different goals, as thats the purpose of them. The purpose of the class should be to process the game, not be the game, which helps it be more portable, reuseable, and expandable.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  8. #8
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    Your "dice" problem results from the fact that the class variables default modifier is not protected, but private. Private variables may not even be accessed by derived classes.

    I'd suggest always putting a qualifier before a block. If you want something to be private, put a private:, if you want it public or protected, put that above the block. Makes it easier to read, too.

    Maybe placing the dice rolling in the player class is not that nice. Make a class of it's own, call it "Dice" and let it have a single static method, taking the number and sides of the dice and return that int.

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    
    class Dice
    {
    	private:
    		Dice()
    		{
    			
    		}
    	public:
    		static int Roll( int number, int sides )
    		{
    			int result = 0;
    
    			for( int i = 0 ; i < number ; i++ )
    			{
    				result += rand() % sides;
    			}
    
    			return result;
    		}
    };
    
    int main()
    {
    	srand( (unsigned)time(NULL) );
    
    	printf( "%d", Dice::Roll( 3, 6 ) );
    
    	return 0;
    }
    Edit: had to edit this code three times... working with C# is bad for your C++ coding skills
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  9. #9
    Registered User
    Join Date
    Jul 2005
    Posts
    20
    Wow, 7 answers already, with lots of good info! Many thanks to all of you.

    I will try to answer all of you, and implement any correction I feel I understand.

    Lets start from the top:


    c+noob:
    i know enough to still provide a destructer because sometimes its a good hbit to make

    ex.
    static constructor();
    virtual ~constructor();
    Hmm... You might be right, sadly I don't know the key words static and virtual. Do you maybe have a link to some good info?



    major_small:
    as for your logic/etc., I haven't taken too much of a look at it, but I did find this spelling error (you missed the last 'h' on health)
    Ugh! A bug! I found an other one myself: "sheriff" was spelled "sherrif".
    Both bugs have been fixed, and the source code compiles much better now! Thank you!
    Seriously though, when I am making a program that outputs text to the user, I really do appreciate being notified of any such spelling errors.
    So thanks again.



    Dae:
    Not a bad start...
    Why, thank you!

    Well first since you are making the player class derived from the human class, you should make a deconstructor in the player class, and set it to virtual: virtual ~human() {}.
    Sounds interesting. Unfortunately, I have absolutely no knowledge of the keyword virtual. What does it do?
    Also.. the compiler does set a default constructor and deconstructor, but neither do anything, so dont expect the default deconstructor to pick up after you.
    Does that mean that the default destructor does NOT free the RAM that the object resided in? And I suppose you mean that the constructor doesn't do anything, besides constructing the object from the class? Or is that a misunderstanding?



    I'm not going to look over the actual coding of how you made the dice roll, or why you are setting dice[numberOfDice]=0; at the end of the function, and just concentrate on OOP concept.
    The answer to the mystery of the insertion of the zero, lies in the sayDice() method. It uses the zero value to determine when there are no more virtual dice in the dice[] array to read. That is also why it is set at dice[0] in the constructor, because there are no dice to read.

    OOP is Object Oriented, so thats the working with objects, not the 'doing everything in the game inside of objects (classes)'.
    OK, so that means that the term "OOP" is more open, and not really confined to "doing everything that relates to the actual program inside seperate objects"?
    Your start game and end game functions would make more sense outside of the player class, why not to because 1) its a bit pointlessly confusing, and 2) the object of the player larger in data, which may not be good in theory if you make more objects of player.
    That's what I'm looking for. Especially number 2), I imagine, is important when trying to develop good habits.

    In your function: int rollDice(int numberOfDice, int sides), I believe you meant to do: if (numberOfDice>9), before you cout....
    That is exactly right. It has been corrected in my working code, Thanks!

    Why are you using getche(); if you dont like it then?
    Good question... I guess the reasons are, that I used it in a calculator I programmed earlier, and it was the only on I knew, besides cin.
    If you have not taken in data using cin <<, then you can simply use cin.get(); to pause. But if you have taken in data using cin <<, when you want to pause use:
    cin.ignore();
    cin.get();
    Cool! Is there maybe a tutorial somewhere, about how those functions work exactly? Maybe cin has more functions?

    You're using some headers that may become deprecated in the future, because they are meant for C, not C++. <iostream.h> should be <iostream>, and you forgot the line: using namespace std;. I'm not sure but I think <stdlib.h> should be <cstdlib>, and I'm not sure about the rest. Headers without .h are meant for C++, headers with .h are meant for C or C++, as some .h's dont have no-extension versions.
    2 down, 2 to go then. I don't count the <string> header, as I believe it is good. Do you know of a good source of info on what headers to use?

    Generally coding style is to capitalize class names..
    What do you mean? Should I call the "player" class "Player" instead??
    and if the function inside of a class is as long as yours are, to seperate it from the class, then use the syntax: type class name::function name (), below the class. Doing this you can seperate the class body and put it in a .h, then #include it into a .cpp where you have the functions using that syntax.
    Noted! I am shure I saw a thread on making includes a few days ago... Will take a look.

    Oh and its not exactly player.rollDice(), its player::rollDice().. thinking about it that way will help.
    That would be when I write to other programmers, and otherwise right? Because the program won't compile if I try to call a method like that...

    Last note.. it seems like you are trying too hard to make use and example using OOP. Put methods that make sense in with classes that make sense, you probably shouldnt just throw in your dice method into the human class just because you're dying to throw something into it. If you're just using it as an example of how to override methods of base classes, alright cool.. but otherwise the player class would usually contain health, stats, what to do when taking damage, etc. and not gamestart, gameover, rolldice.
    Sure, you are right. I am trying much too hard to cram stuff into that class. However, I did seriously consider giving each character in the game his own set of dice, but even so, I definitely shouldn't write it directly into the human class, as dice are not a part of the human anatomy.
    Not even digital speciments.
    Please correct me if this is not right, or something seems unclear.

    Also when coding try it make it readable, which falls under 1) splitting up the class from the long methods, and seperating them into the files, 2) good tabbing/spacing, which you do have, 3) good, consistant coding style, well yours is half way there.
    1) I'm working on it. 2) Thanks alot! I put a lot of effort into it. 3) Any tips would be appreciated!
    I would recommend using a common coding style for all of your code, but that may be a little bit to take in right now, if not I'll paste it, its about naming your variables, classes, objects, and functions, I've noticed it in code, and read it in books.
    Sure! Let me at it! If it is too hard to handle, I can always put it aside, but I have a feeling that something like this would be smart to do, right from the start.



    quzah:
    Any elements of an array which you do not initialize, provided you have initialized at leats one of them, will be set to zero. Thus:
    Code:

    int foo[ BAR ] = {0};
    Does that mean that if I declared the dice[] array like this:
    Code:
    int dice[10] = {0};
    all the cells in the dice[] array would initialy be set to 0?



    Dae again:
    Your second post clears up a lot about how to structure my classes and (along with quzah's post) makes me realize that I need to read up on arrays.



    nvoigt:
    Your "dice" problem results from the fact that the class variables default modifier is not protected, but private. Private variables may not even be accessed by derived classes.
    Thanks for clearing that up! It is misunderstandings like this that I really want to avoid, right from the start. If you see anything else in my comments, that is wrong or just seems unclear, please let me know!

    I'd suggest always putting a qualifier before a block. If you want something to be private, put a private:, if you want it public or protected, put that above the block. Makes it easier to read, too.
    That seems like a very sensible practice, and I will try to incorporate it right away.
    Also, I call it "protection level". Is qualifier the correct term for that?

    As to your suggestion on defining the dice in its own class, I might do just that. Although, I am still very unshure as to how the whole thing will be linked together.



    Humongous post again, but a lot to anwer too. Thank you all for making an effort to assist me! I really appreciate it!

    I will include a short todo list:
    • Read up on arrays (resize).
    • Stripp unwanted features from human class.
    • Sepparate long methods from class body.
    • Read C Board on making header files.
    Once again, if anyone has any suggestions or additions.... You know what to do.

  10. #10
    *this
    Join Date
    Mar 2005
    Posts
    498
    ex.
    static constructor();
    virtual ~constructor();
    Constructors cant be static. It may be a good habit but you only need them when you have to assign private/public/protected data members or clean them up.
    Last edited by JoshR; 07-15-2005 at 12:18 AM.

  11. #11
    *this
    Join Date
    Mar 2005
    Posts
    498
    A virtual function allows the function to be modified via another class or struct etc...

    For example if you have a base class and a derived class

    Code:
    #include <iostream>
    using namespace std;
    
    class base {
       public: 
          base () { };
          virtual void print () { cout << "base"; };
       private:
    };
    
    class derived : public base {
       public:
          derived () { };
          void print () { cout << "derived"; };
       private:
    };
    
    main () {
       base b;
       derived d;
       
       b.print();
       cout << endl;
       d.print();
       
       cin.get();
       return 0;
    }

  12. #12
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by muggizuggi
    Sounds interesting. Unfortunately, I have absolutely no knowledge of the keyword virtual. What does it do?Does that mean that the default destructor does NOT free the RAM that the object resided in? And I suppose you mean that the constructor doesn't do anything, besides constructing the object from the class? Or is that a misunderstanding?
    Thats right, default deconstructor does not free allocated memory for the object. I dont believe the constructor constructs the object, the object is a copy of the class to edit essentially, and the constructor is simply called on the creation of a copy of the class (object) (which the compiler handles), and the deconstructor is called when it is deleted or goes out of scope. The default constructor is ~ClassName () {}, default constructor is ClassName () {}.. they aint going much. I may be incorrect about the class/object theory though, havent read into that really, just know how to use them.

    Quote Originally Posted by muggizuggi
    The answer to the mystery of the insertion of the zero, lies in the sayDice() method. It uses the zero value to determine when there are no more virtual dice in the dice[] array to read. That is also why it is set at dice[0] in the constructor, because there are no dice to read.
    Ohh I didnt go through the code enough to see that if statement. I also apparently missed the fact that you were trying to use the base classes private array, from the derived class that only derives from public.. but another poser pointed that out.

    Quote Originally Posted by muggizuggi
    OK, so that means that the term "OOP" is more open, and not really confined to "doing everything that relates to the actual program inside seperate objects"?That's what I'm looking for. Especially number 2), I imagine, is important when trying to develop good habits.
    Essentially. let me correct what I said: "why not to have gamestart/over in class player/human 1) its a bit pointlessly confusing, and 2) the object of the player will get bigger in data, which may not be good in theory if you make more objects of player (not that that would work the way you have it)."

    The gamestart/over functions would be better as stand alone functions. Call gamestart in the beginning of int main(), and call gameover() whenever it is necessary: in some menu, the player selects go back to main menu, or in the player class, if players health is == 0 (use an unsigned int to track health as it will not go into negative numbers). That points out another reason not to have gameover() in the player class, as your menu most likely wont be in the player class too, which means to call gameover() you would have to create an object of player class and call gameover().. now that would.. make no sense to me

    Quote Originally Posted by muggizuggi
    What do you mean? Should I call the "player" class "Player" instead??
    Yup, most people capitalize their classes, and that may sound lame being like most people, but that means most people can read your code easier.

    Quote Originally Posted by muggizuggi
    That would be when I write to other programmers, and otherwise right? Because the program won't compile if I try to call a method like that...
    No I just meant in your error messages:
    "Error! player.sayDice(): No dice were rolled." << endl
    By saying player.sayDice() you are saying theres a problem with the sayDice() method in the object: 'player', 'player' isnt your object, it is your class, there is a big difference.

    Quote Originally Posted by muggizuggi
    Sure, you are right. I am trying much too hard to cram stuff into that class. However, I did seriously consider giving each character in the game his own set of dice, but even so, I definitely shouldn't write it directly into the human class, as dice are not a part of the human anatomy.
    Not even digital speciments.
    Please correct me if this is not right, or something seems unclear.
    Well.. its more like are coca cola, pepsi, and sprite all kinds of the same? yeah, then essentially you could put them in the same class: pop types (or derived them), even if you need some kind of ice cubes with them, you dont put it in the pop class, you either make it a seperate function/class and then just call it from inside the pop class ( AddCube(); ). This allows you to re-use that ice cube class/function for other things/projects without accessing the pop class/removing it from the interworks of the pop class. Basicly, like said above, if you want a roll dice, etc. function, then it should be best to call it where necessary in the Player class, and have it defined else where.

    Quote Originally Posted by muggizuggi
    3) Any tips would be appreciated!Sure! Let me at it! If it is too hard to handle, I can always put it aside, but I have a feeling that something like this would be smart to do, right from the start.
    Well other than yes, capitalizing your Classes/Structures/Functions, I have my own preferences. I didnt really think about it until I read it, but it makes sense to prefix things/have a style that can be easier to follow. I prefer putting C/S infront of Classes/Structures, but thats just me, a large many put g_, m_, p_, but others might put i, ii, iii as prefixes, or nothing. After thinking about the options, its all just what you prefer.

    Code:
    Global variables will be prefixed with g_.
    Examples: g_name, g_state
    
    Class/Structure members variables will be prefixed with m_.
    Examples: m_name, m_state
    
    Parametere variables will be prefixed with p_.
    Examples: p_name, p_state
    
    Local function variables will have no prefix.
    Examples: name, state
    
    Class/Structure names will be title_cased, with each major word in the name capitalized, and seperated by an underscore.
    Examples: Class_One, Class_Two, Structure_One
    
    Function names will be title_cased, with each major word in the name capitalized.
    Examples: FunctionOne (), FunctionTwo ()
    
    Objects of Class/Structure will have each major word in the name capitalized, but will contain no underscores or prefixed capital letter.
    Examples: Class_One SomeClass, Structure_One SomeStructure
    
    ALL brackets in general will be seperated from variable, function, loop, etc. with one space.
    Examples: for (i = 0; i < this; ++i), FunctionOne (&avariable), int main ()
    
    Two spaces will be used for indentations, not tabs or large amount of spaces.
    Mostly everything I said to you I learned from an eBook (as thats the only book I've read on C++ so far, besides trial and error and 4 tutorials): http://newdata.box.sk/bx/c/, note: it may be an illegal ebook, im not sure, so you may not want to go to it. Generally you'll learn most OOP in basics up C++ book, but if you dont want to spend money you can try and find free ebooks (and yes, there are some free ones companies that make the book distribute).

    Virtual functions are to allow derived classes to override (replace) the function. In JoshR's example if you hadn't declared the print() function in the derived class, then calling print() from the derived class would show the base classes print(). Theres more information than that, which is all wrapped up in inheritance, and virtual inheritance. (http://newdata.box.sk/bx/c/htm/ch12.htm)

    Reason for Virtual Deconstructor: It is legal and common to pass a pointer to a derived object when a pointer to a base object is expected. What happens when that pointer to a derived subject is deleted? If the destructor is virtual, as it should be, the right thing happens--the derived class's destructor is called. Because the derived class's destructor will automatically invoke the base class's destructor, the entire object will be properly destroyed. If the deconstructor of the base class is not virtual, then the base class deconstructor will not be called, and result in a bad bug.

    The rule of thumb is this: If any of the functions in your class are virtual, the destructor should be as well. Which just prevents you from having to worry about this rare occurance where the base deconstructor isnt called.
    Last edited by Dae; 07-15-2005 at 02:19 AM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  13. #13
    Registered User Jaqui's Avatar
    Join Date
    Feb 2005
    Posts
    416
    here is an example of a php code that is well commented.
    10 years from now this will still make sense, because of the comments.

    ( only code I had sitting around that shows a good ( maybe excessive ) way to comment code )

    Code:
    <?php
    /*
    ********************************************************
    *** This script from MySQL/PHP Database Applications ***
    ***         by Jay Greenspan and Brad Bulger         ***
    ***                                                  ***
    ***   You are free to resuse the material in this    ***
    ***   script in any manner you see fit. There is     ***
    ***   no need to ask for permission or provide       ***
    ***   credit.                                        ***
    ********************************************************
    */
    
    // void authenticate ([string realm] [, string error message]])
    
    // Send a WWW-Authenticate header, to perform HTTP authentication.
    // The first argument is the text that will appear in the pop-up
    // form presented to the user. The second argument is the text
    // that will appear on the 401 error page if the user hits the
    // 'Cancel' button in the pop-up form.
    
    // This code only works if PHP is running as an Apache module.
    
    function authenticate ($realm="Secure Area"
    	,$errmsg="Please enter a username and password"
    )
    {
    	Header("WWW-Authenticate: Basic realm=\"$realm\"");
    	Header("HTTP/1.0 401 Unauthorized");
    	die($errmsg);
    }
    
    
    // void db_authenticate([string table [, string realm [, string error message [, string username field name [, string password field name]]]])
    
    // Uses HTTP authentication to get a user name and password, and then
    // verifies that against a database table. The first argument is the
    // name of the table to use - the default is mysql.users.  The second
    // and third arguments are passed in to the authenticate() function.
    // The fourth and fifth arguments are the names of the fields in the
    // database table - default values are 'username' and 'password'.
    
    // This code only works if PHP is running as an Apache module.
    
    function db_authenticate($table="mysql.users",$realm="Secure Area"
    	,$errmsg="Please enter a username and password"
    	,$user_field=""
    	,$password_field=""
    )
    {
    	global $PHP_AUTH_USER;
    	global $PHP_AUTH_PW;
    
    	if (empty($PHP_AUTH_USER))
    	{
    		authenticate($realm,$errmsg.": header");
    	}
    	else
    	{
    		if (empty($user_field)) { $user_field = "username"; }
    		if (empty($password_field)) { $password_field = "password"; }
    
    		$query = "select $user_field from $table 
    			where $password_field = password(lower('$PHP_AUTH_PW')) 
    			and $user_field = lower('$PHP_AUTH_USER')
    		";
    		$result = safe_query($query);
    		if ($result) { list($valid_user) = mysql_fetch_row($result); }
    		if (!$result || empty($valid_user))
    		{ 
    			authenticate($realm,$errmsg.": query");
    		}
    	}
    	#print "<h5>Editing as $PHP_AUTH_USER</h5>\n";
    }
    
    // string cleanup_text ([string value [, string preserve [, string allowed_tags]]])
    
    // This function uses the PHP function htmlspecialchars() to convert
    // special HTML characters in the first argument (&,",',<, and >) to their 
    // equivalent HTML entities. If the optional second argument is empty,
    // any HTML tags in the first argument will be removed. The optional
    // third argument lets you specify specific tags to be spared from
    // this cleansing. The format for the argument is "<tag1><tag2>".
    
    function cleanup_text ($value = "", $preserve="", $allowed_tags="")
    {
    	if (empty($preserve)) 
    	{ 
    		$value = strip_tags($value, $allowed_tags);
    	}
    	$value = htmlspecialchars($value);
    	return $value;
    }
    
    // string get_attlist ([array attributes [,array default attributes]])
    
    // This function will take an associative array and format as a string
    // that looks like 'name1="value1" name2="value2"', as is used by HTML tags.
    // Values for keys in the first argument will override values for the
    // same keys in the second argument. (For example, if $atts is (color=>red)
    // and $defaults is (color=>black, size=3), the resulting output will
    // be 'color="red" size="3"'.)
     
    function get_attlist ($atts="",$defaults="")
    {
    	$localatts = array();
    	$attlist = "";
    
    	if (is_array($defaults)) { $localatts = $defaults; }
    	if (is_array($atts)) { $localatts = array_merge($localatts, $atts); }
    
    	while (list($name,$value) = each($localatts))
    	{
    		if ($value == "") { $attlist .= "$name "; }
    		else { $attlist .= "$name=\"$value\" "; }
    	}
    	return $attlist;
    }
    
    // string make_page_title ([string title])
    
    // This function will clean up a string to make it suitable for use
    // as the value of an HTML <TITLE> tag, removing any HTML tags and
    // replacing any HTML entities with their literal character equivalents.
    
    function make_page_title ($title="")
    {
    	$title = cleanup_text($title);
    	$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
    	$title = strtr($title, $trans); 
    	return $title;
    }
    
    // string money ([mixed value])
    
    // This function will format the first argument as a standard US dollars
    // value, rounding any decimal value two decimal places for cents 
    // and prepending a dollar sign to the returned string.
    
    function money($val=0)
    {
    	return "$".number_format($val,2);
    }
    
    // array states(void)
    
    // This function will return an associative array of US states,
    // with the two-letter abbreviation as the key and the full name
    // as the value.
    
    function states()
    {
    	$states['AL'] = "Alabama";
    	$states['AK'] = "Alaska";
    	$states['AS'] = "American Samoa";
    	$states['AZ'] = "Arizona";
    	$states['AR'] = "Arkansas";
    	$states['CA'] = "California";
    	$states['CO'] = "Colorado";
    	$states['CT'] = "Connecticut";
    	$states['DE'] = "Delaware";
    	$states['DC'] = "District Of Columbia";
    	$states['FM'] = "Federated States Of Micronesia";
    	$states['FL'] = "Florida";
    	$states['GA'] = "Georgia";
    	$states['GU'] = "Guam";
    	$states['HI'] = "Hawaii";
    	$states['ID'] = "Idaho";
    	$states['IL'] = "Illinois";
    	$states['IN'] = "Indiana";
    	$states['IA'] = "Iowa";
    	$states['KS'] = "Kansas";
    	$states['KY'] = "Kentucky";
    	$states['LA'] = "Louisiana";
    	$states['ME'] = "Maine";
    	$states['MH'] = "Marshall Islands";
    	$states['MD'] = "Maryland";
    	$states['MA'] = "Massachusetts";
    	$states['MI'] = "Michigan";
    	$states['MN'] = "Minnesota";
    	$states['MS'] = "Mississippi";
    	$states['MO'] = "Missouri";
    	$states['MT'] = "Montana";
    	$states['NE'] = "Nebraska";
    	$states['NV'] = "Nevada";
    	$states['NH'] = "New Hampshire";
    	$states['NJ'] = "New Jersey";
    	$states['NM'] = "New Mexico";
    	$states['NY'] = "New York";
    	$states['NC'] = "North Carolina";
    	$states['ND'] = "North Dakota";
    	$states['MP'] = "Northern Mariana Islands";
    	$states['OH'] = "Ohio";
    	$states['OK'] = "Oklahoma";
    	$states['OR'] = "Oregon";
    	$states['PW'] = "Palau";
    	$states['PA'] = "Pennsylvania";
    	$states['PR'] = "Puerto Rico";
    	$states['RI'] = "Rhode Island";
    	$states['SC'] = "South Carolina";
    	$states['SD'] = "South Dakota";
    	$states['TN'] = "Tennessee";
    	$states['TX'] = "Texas";
    	$states['UT'] = "Utah";
    	$states['VT'] = "Vermont";
    	$states['VI'] = "Virgin Islands";
    	$states['VA'] = "Virginia";
    	$states['WA'] = "Washington";
    	$states['WV'] = "West Virginia";
    	$states['WI'] = "Wisconsin";
    	$states['WY'] = "Wyoming";
    	$states['AE'] = "Armed Forces Africa";
    	$states['AA'] = "Armed Forces Americas";
    	$states['AE'] = "Armed Forces Canada";
    	$states['AE'] = "Armed Forces Europe";
    	$states['AE'] = "Armed Forces Middle East";
    	$states['AP'] = "Armed Forces Pacific";
    
    	return $states;
    }
    
    // string get_local_ref ([string ref])
    
    // This function will transform a local reference (such as "edit.php")
    // to a local reference that begins with the root of the current
    // script as defined by the Apache variable SCRIPT_NAME (such as
    // "/book/guestbook/view.php"). It is used by the secure_url()
    // and regular_url() functions to create an absolute URL out of
    // a local reference.
    
    // This behavior of this function if run under a server other than Apache
    // is not known. It's likely to work, though, as SCRIPT_NAME is part of
    // the CGI 1.1 specification.
    
    function get_local_ref($ref="")
    {
    	global $SCRIPT_NAME;
    
    	if (substr($ref,0,1) != "/")
    	{
    		$ref = substr($SCRIPT_NAME,0,strrpos($SCRIPT_NAME,"/")+1).$ref;
    	}
    	return $ref;
    }
    
    // string secure_url ([string ref])
    
    // This function will transform a local URL into an absolute URL pointing
    // to a secure server running on the same domain, as defined by the global
    // Apache variable HTTP_HOST. (Note: the server we are using runs on 
    // non-standard ports, thus the need to change the port numbers.)
    
    function secure_url($ref="")
    {
    	global $HTTP_HOST;
    
    	$url = "https://".$HTTP_HOST.get_local_ref($ref);
    	$url = str_replace("8080","444",$url);
    	return $url;
    }
    
    // string regular_url ([string ref])
    
    // This function will transform a local URL into an absolute URL pointing
    // to a normal server running on the same domain, as defined by the global
    // Apache variable HTTP_HOST. (Note: the server we are using runs on 
    // non-standard ports, thus the need to change the port numbers.)
    
    function regular_url($ref="")
    {
    	global $HTTP_HOST;
    
    	$url = "http://".$HTTP_HOST.get_local_ref($ref);
    	$url = str_replace("444","8080",$url);
    	return $url;
    }
    
    include("../functions/db.php");
    include("../functions/html.php");
    include("../functions/forms.php");
    include("../functions/tables.php");
    
    ?>
    okay, so it's from a manual's cdrom on php and mysql, it's still an example of commenting to allow for understanding the code at a latter date.

  14. #14
    Registered User
    Join Date
    Jul 2005
    Posts
    20
    Hello again,

    This is just a quick post to tell you all that I am still working hard on the homework that you have already given me.
    Thank you all so much!
    Especially you, Dae, for spending so much time on me.
    I really hope I can make it up to you when I am actually worth something, as a programmer.

    And Jaqui - that example really does help alot. I will try to incorporate that style of commenting in my next example.

    Also - quzah - that question about initializing arrays... It was just as easy to test it, as it was to ask the question.
    Guess I was just too tired that time.


    One more thing: About the cin.get() function - this is what I've got so far:

    There is something called a stream, that holds data (a string?) for the cin functions. In order to make cin.get() pause the program, said stream needs to be empty (or the next "character" has to be newline?). That means, that if you have previously put data into the stream, you should first clear it using cin.ignore().

    Is that right?

    OK, enough babling. I need to sleep...

    [edit]
    Oops - I forgot 1 thing...
    JoshR, if I remove "virtual" from your code example, the program still does exactly the same.
    I am using Dev-c++ under Windows XP to compile (that would be MinGW, I think).
    Any way - I am still strugling hard with that virtual thingy.
    Last edited by muggizuggi; 07-16-2005 at 10:33 PM.

  15. #15
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quick suggestion: dont read anything I write, as I tend to run on about nothing.. a lot (see, I just did it there).

    Quote Originally Posted by muggizuggi
    One more thing: About the cin.get() function - this is what I've got so far:

    There is something called a stream, that holds data (a string?) for the cin functions. In order to make cin.get() pause the program, said stream needs to be empty (or the next "character" has to be newline?). That means, that if you have previously put data into the stream, you should first clear it using cin.ignore().

    Is that right?
    I believe that get() extracts a character from the stream, and returns it, but if there is no character in the stream (you've cleared it, or its never been used: ie. when you havent used cin << yet) it pauses. The fact that you can call cin.get() many concecutive times implies that even though you can enter something into cin.get(), it doesnt add it to the stream, its simply pausing. Of course to confirm this I'd probably have to look at the code, which I've never done. Hell, I've only checked about 4 functions from the standard's parameters, from the reference: http://www.cplusplus.com/ref/

    Quote Originally Posted by muggizuggi
    [edit]
    Oops - I forgot 1 thing...
    JoshR, if I remove "virtual" from your code example, the program still does exactly the same.
    I am using Dev-c++ under Windows XP to compile (that would be MinGW, I think).
    Any way - I am still strugling hard with that virtual thingy.
    Since I've only read one C++ book, and not a good on at that, I dont even know why you can remove the virtual keyword and it still works. In that ebook I recommended (that I dont recommend anymore) it shows you how you derive and override functions without using the virtual keyword, and then simply starts adding them. I'm just assuming because the book didnt say why it started adding the virtual keyword: that using the virtual keyword is just to clarify that you plan to override that function in derived classes. Of course if this isnt the only reason, then that book sucks even more.

    I've only got a small grasp on the works of virtual inheritance and polymorphism, so I'm not going to be able to help with that.. I dont plan on reading anymore on the subject until I order a book worth reading off amazon.com: C++ Primer Plus, (5th Edition)
    by Stephen Prata, and The C++ Programming Language, (Special 3rd Edition), by Bjarne Stroustrup. I researched many books, and these books both come off as great teaching books, as well as remain beside your computer as references. Along with Data Structures for Game Programmers, which affirms most of your knowledge, and not only teaches basic methods of data structures for games (storing in arrays, saving the data, linked lists, player class), but gives you a good vision of how to use OOP with your game. If you have the means.. these three books would get through it so quicky. Basicly.. I'm sitting here typing this and drooling at my own comments: I'm going to order these books ASAP.

    By the way, although deriving is good in certain cases and everything. But have you see the Quake 1-3 source code, and other game source code? Not only do they barely ever, if once, use derived classes, but they barely even use classes: they generally just have a function for each thing they need to do, along with many structures (same as classes essentially). Why I mention this is that it might make it easier to plan it out like that first. The bottom up method, where you plan functions that you need to do certain things, then make them, then you can group them, or change them, into classes or derived classes as necessary later. Making a class for a purpose and then trying to think of functions to go along with it, the top down method, can be much harder. Just a suggestion, might not work.. but if youve ever looked over game code it, so you have an idea of the functions of the game, it might make it easier.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A Simple Question,Answer would be Highly Appreciated.
    By parastar in forum C Programming
    Replies: 8
    Last Post: 01-29-2009, 09:34 AM
  2. Looking for constructive criticism
    By wd_kendrick in forum C Programming
    Replies: 16
    Last Post: 05-28-2008, 09:42 AM
  3. Constructive criticism, suggestions etc
    By BobS0327 in forum C Programming
    Replies: 3
    Last Post: 01-08-2006, 09:35 AM
  4. Review and criticism appreciated!
    By Sysop_fb in forum C Programming
    Replies: 9
    Last Post: 09-28-2005, 01:48 PM