![]() |
| | #1 |
| Registered User Join Date: Dec 2002
Posts: 1
| |
| sana is offline | |
| | #2 |
| Registered User Join Date: Jul 2002
Posts: 66
| in C++ a structure and class are the same except a class is private by default and a structure is public by default. There's no comparison with a C structure because it can't have methods, just members. |
| Crimpy is offline | |
| | #3 |
| Programming Sex-God Join Date: Nov 2002
Posts: 1,078
| In C, the only thing a structure could do was allow to you store multiple variables in one structure and allow for bitfields. A class/struct in C++ is much much more. First, there is the introduction of member functions. In C, if you had a player struct, for example, and you wanted it to "attack," you'd create an attack function and pass the address of the struct to the function. In C++, however, there is the introduction of member functions. Basically, what that allows you to do is think of the Player as attacking rather than "attack" being a procedure which takes a parameter of a player. //////// C Style Attack( &MyPlayer ); // Attack with my player C++ Style MyPlayer.Attack(); // Make MyPlayer attack //////// It is important to note that, at this point, both examples do the same thing internally, it's just the way of thinking about the interaction that's different. It makes you think more of the player as being an object that can actually do things, rather than just being a clump of data used for a procedure. Then, there is the concept of varying access. What if you had a member of the struct that you used interally, but you don't want people to have direct access to -- you only want it to be able to be accessed by a member function like attack in the C++ example. A better example of this would be a class that represents an array that can be of different lengths and different places in memory. You wouldn't want people to be able to access that data directly because if they change it without using a member function, they might "break" the object. IE -- you don't want someone to directly change the size variable from 3 to 4 without reallocating the array. The same concept is used with functions -- you might want a function that can only be used internally rather than by other people who are just using an instance of the class directly. So, you have access specifiers. In C++ there are 3: public private protected For now, I'll just go into the first 2. public gives you all access to the variable private makes it so that only the class can access the variable The way you use them is by placing the access specifier name followed by a colon within the class definition followed by any variables and/or functions that you want to have that type of access. Code: class IntArray
{
public:
void Resize( unsigned int NewSize ); // Can be accessed through an object
private:
int* DynamicArray; // Can't be accessed externally
unsigned int Length; // Can't be accessed externally
};
But, if you have experience with dynamic memory allocation right now, there should be another problem that you can see: If you don't give access to the DynamicArray pointer, how do you use it to allocate memory and deallocate the memory once it's allocated? Once solution might be to make 2 functions -- one for allocating and one for deallocating that can be used externally... but there is a better way in C++. I'll leave behind the array example for now, but I'll get back to it. Introducing constructors and destructors!!! Back in C, in order to initialize a struct you had to do something similar to the way you initialized an array: Code: struct Player
{
int CurrentHealth;
int CurrentArmor;
}; // This was the Player struct declaration
The problem with this is that it forces the user to know exactly the implementation of the player structure and even the order. It also only allow one way for the person to construct the Player. What is, for instance, you wanted to pass it an enumerated value to represent a common preset health/Armor that the structure would be able to figure out the Armor and Health the player should have? In C++ you can do that with constructors: The concept is, every time you create an object, a function used for initializing the object is called! You have the control of what the constructor does, and you can even make multiple constructors -- as many as you want and for all different situatons. The way you make a constructor is you create a function with no return value (not even void), that takes whatever parameters you want! Code: enum CommonHealth { NoHealth = 0, FullHealth = 1 };
class Player
{
public:
Player( CommonHealth HealthInit );
private:
int CurrentHealth;
int CurrentArmor;
};
Player MyPlayer( FullHealth ); // Construct the object with "FullHealth" Before I go any further, let's talk about how to actually define these "member functions." It's very similar to defining standard functions. You specify the return value followed by the classname followed by the double colon scope operator followed by the name of the member function and it's parameters. Code: enum CommonHealth { NoHealth = 0, FullHealth = 1 };
class Player
{
public:
Player( CommonHealth HealthInit );
int GetHealth() const; // Return the current health. I'll explain const later
private:
int CurrentHealth;
int CurrentArmor;
};
Player::Player( CommonHealth HealthInit )
{
if( HealthInit == 0 )
CurrentArmor = CurrentHealth = 0;
else
if( HealthInit == 1 )
{
CurrentHealth = 100;
CurrentArmor = 50;
}
}
int Player::GetHealth() const
{
return CurrentHealth;
}
Player MyPlayer( FullHealth ); printf( "%d", MyPlayer.GetHealth() ); and you will output the amount of health the player has (I'm assuming you are familiar with printf, if not, you just have to know that all it will do is print out whatever MyPlayer.GetHealth() returns as an integer). In this case, it should output 100 because that's what we made the constructor set the value to when passed "FullHealth" as a parameter. Now -- const I'm sure you've used const before, so I'll make this quick. Going back to the original C example: C Style Attack( &MyPlayer ); // Attack with my player C++ Style MyPlayer.Attack(); // Make MyPlayer attack What if you wanted to be able to pass a pointer to a constant player to the attack function? The attack function will not alter any of the player data, so you should be able to pass a constant. In C, you know how to do this: Code: // Declare the function to use a pointer to a constant void Attack( const Player* Attacker ); Okay, now that we have talked about constructors, let's get into a case where you'd want to "destruct" your data. The most common time you'd have to do this is with dynamic memory allocation -- like the IntArray example I gave earlier. The syntax for declaring a destructor is similar to that of a constructor. You create it like a member function without a return type, only this time, you give it the name of the classtype preceeded by a tilde ~. You define it just like any other member function. There can be only 1 destructor, unlike constructors, and the destructor is automatically called when the object is deleted. So, let's get back to that IntArray example! Code: class IntArray
{
public:
IntArray( unsigned int LengthInit ); // Make a constructor for the initial size
~IntArray(); // Make a destructor for deallocating memory
void Resize( unsigned int NewSize ); // Can be accessed through an object
private:
int* DynamicArray; // Can't be accessed externally
unsigned int Length; // Can't be accessed externally
};
IntArray::IntArray( unsigned int LengthInit )
: Length( LengthInit ) // This initializes the length datamember to LengthInit.
{
DynamicArray = new int[Length]; // This is how you dynamically allocate in C++
}
IntArray::~IntArray()
{
delete [] DynamicArray; // This is how you dynamically deallocate arrays in C++
}
Code: int main()
{
IntArray( 5 ); // Make an array of length 5
return 0;
}
Now, everything so far is really just syntactical difference from C, except for the automatic calling of the constructors/destructor. Now let's go into the fun stuff -- what really makes OOP powerful!!! Inheritance... Let's say you want enemies in your game. More importantly, let's say you have enemies of different types. They are all related because they are all "enemies," but how do we represent this relationship in C++ I'm going to through out a quick example with no implementation just yet, just so you can see the relationship between the objects and the syntax. Code: class Enemy // A type that we will derive other "enemies" from
{
public:
int GetHealth() const;
private:
int Health;
};
class SmallEnemy
: public Enemy // SmallEnemy is a kind of Enemy
{
};
class BigEnemy
: public Enemy // BigEnemy is also a kind of Enemy
{
};
You have a sort of abstract concept of an enemy, and you have two kinds of enemies -- a big enemy and a small enemy. Notice that we said "enemy" has health. We said that SmallEnemy and BigEnemy are both "kinds of" enemies. Does this mean that they have health and a function "GetHealth" as well? Yes!!! That's all well and good... but right now, all we've done is saved us a couple of lines of typing... There's much more power to it than that... Take this example... Code: Enemy MyEnemy; SmallEnemy MySmallEnemy; BigEnemy MyBigEnemy; MyEnemy.GetHealth(); // Works MySmallEnemy.GetHealth(); // Works MyBigEnemy.GetHealth(); // Works Enemy* AnEnemy; AnEnemy = &MyEnemy; // We know this works // ... Hmm... but maybe... AnEnemy = &MySmallEnemy; AnEnemy = &MyBigEnemy; // Do they work? ...Yes! Okay... now, remember when I said there were 3 access specifiers public private protected I only talked about public and private because protected only comes into play with this "inheritance" What protected means is that you can access the data in a "base class" from a "child" class, unlike private. so Code: class Privates
{
private:
int Data;
};
class DerivedPrivates
: public Privates
{
public:
int GetData() const;
};
class Protecteds
{
protected:
int Data;
};
class DerivedProtecteds
: public Protecteds
{
public:
int GetData() const;
};
int DerivedPrivates::GetData() const
{
return Data; // Error, can't access Data
}
int DerivedProtecteds::GetData() const
{
return Data; // Success
}
Let's get back to the enemy example. As I said, we have 2 types of enemies. We know that both kinds of enemies have to be able to attack, but what if we want them to attack... differently. Can we just redefine the function in "child" types? If so, will the appropriate function be called with the proper object... what if it's through a pointer to the base, will the appropriate function be called there as well? Imagine that the BigEnemy might attack with a battleaxe instead of an Enemy's sword -- if we assign the address of a BigEnemy to an EnemyPointer and called the Attack function, will he use a sword (as defined by the Enemy type) or a battleaxe (as defined by the BigEnemy type)? If it uses the battleaxe, imagine the power that gives you, as a programmer! Code: class Enemy
{
public:
void Attack();
int GetHealth() const;
private:
int Health;
};
class SmallEnemy
: public Enemy
{
public:
void Attack();
};
class BigEnemy
: public Enemy
{
public:
void Attack();
};
/* Let's now stop and say that we defined Attack differently for each of the objects.
I won't actually go and define them now, because it would take too long (and this
post is already a bit longer than I think you were expecting, heh) */
int main()
{
Enemy SomeEnemy;
SmallEnemy SomeSmallEnemy;
BigEnemy SomeBigEnemy;
SomeEnemy.Attack(); // Calls the Enemy's unique attack function
SomeSmallEnemy.Attack(); // Calls the SmallEnemy's unique attack function
SomeBigEnemy.Attack(); // Calls the BigEnemy's unique attack function
// Now let's make things interesting...
Enemy* EnemyPointer;
EnemyPointer = &SomeEnemy;
EnemyPointer->Attack(); // Calls the Enemy's attack function
EnemyPointer = &SomeSmallEnemy;
EnemyPointer->Attack(); // DAMN! It calls the Enemy's attack function
EnemyPointer = &SomeBigEnemy;
EnemyPointer->Attack(); // DAMN! It calls the Enemy's attack
return 0;
}
virtual Code: class Enemy
{
public:
virtual void Attack(); // notice the keyword virtual
int GetHealth() const;
private:
int Health;
};
class SmallEnemy
: public Enemy
{
public:
void Attack();
};
class BigEnemy
: public Enemy
{
public:
void Attack();
};
int main()
{
Enemy SomeEnemy;
SmallEnemy SomeSmallEnemy;
BigEnemy SomeBigEnemy;
SomeEnemy.Attack(); // Calls the Enemy's unique attack function
SomeSmallEnemy.Attack(); // Calls the SmallEnemy's unique attack function
SomeBigEnemy.Attack(); // Calls the BigEnemy's unique attack function
// Now let's make things interesting...
Enemy* EnemyPointer;
EnemyPointer = &SomeEnemy;
EnemyPointer->Attack(); // Calls the Enemy's attack function
EnemyPointer = &SomeSmallEnemy;
EnemyPointer->Attack(); // !!! It calls the SmallEnemy's attack function
EnemyPointer = &SomeBigEnemy;
EnemyPointer->Attack(); // !!! It calls the BigEnemy's attack
return 0;
}
Just think of some of the uses -- you can now have an array of enemies, cycle through them -- calling each of their attack functions, and depending on whether they are BigEnemies, SmallEnemies, or any number of an infinite amount of enemy types there are, the appropriate version of "attack" gets called. Oh, the mighty power of virtual! ![]() Great! Now, let's say you want to derive one class from MULTIPLE other classes. For instance, what if you have a car class and a van class. You want a minivan. Let's derive the minivan from BOTH the car AND the van. All you have to do is separate the parent classes by a comma in the derivation. Code: class Car
{
};
clas Van
{
};
class MiniVan
: public Car, public Van // Derive from both a Car and a Van
{
};
But with multiple inheritance comes a lot of problems, though not ones without solutions. Say you want a minivan like the previous example, but your Car and MiniVan are both derived from a "Vehicle" class. That means that any datamembers that were in the base class would have two instances int the minivan class (one from the Car and one from the MiniVan) and their names would be the same. Now, not only do you have two variables where you only want one, but when you use the name it's ambiguous! which one are you referring to! So, the keyword virtual comes back, only this time in a different way. Code: class Vehicle
{
public:
int Data;
};
class Car
: public virtual Vehicle
{
};
class Van
: public virtual Vehicle
{
};
class MiniVan
: public Car, public Van
{
};
MiniVan MyVehicle; MyVehicle.Data; // Now refers to one single Data shared by the "Car part" and the "Van part" of MiniVan. ...Oh yeah, and structs default to public access while classes default to private... EDIT: Long comment in code forced horizontal scrolling in browser Last edited by Polymorphic OOP; 12-01-2002 at 08:09 PM. |
| Polymorphic OOP is offline | |
| | #4 |
| ¡Amo fútbol! Join Date: Dec 2001
Posts: 2,121
| Buddy, have a little time on your hands? |
| golfinguy4 is offline | |
| | #5 |
| Programming Sex-God Join Date: Nov 2002
Posts: 1,078
| Yeah, I lost a girlfriend once because I just code all day and post in forums and stuff. She said I like programming more than being with her. ... which was true, but... wait... what was my point? Oh yeah, programming rules! Social life can SUCK IT! |
| Polymorphic OOP is offline | |
| | #6 |
| Guest Join Date: Aug 2001
Posts: 4,923
| Dedication. Devotion. Great attitude. |
| Sebastiani is offline | |
| | #7 |
| Code Goddess Join Date: Sep 2001
Posts: 9,661
| >Yeah, I lost a girlfriend once because I just code all day and post in forums and stuff. I need to find a guy like that, the ones I date don't seem to understand that they aren't as interesting as my computer. ![]() >Oh yeah, programming rules! Social life can SUCK IT! Amen ![]() -Prelude
__________________ My best code is written with the delete key. |
| Prelude is offline | |
| | #8 |
| Programming Sex-God Join Date: Nov 2002
Posts: 1,078
| Marry me |
| Polymorphic OOP is offline | |
| | #9 |
| Skunkmeister Join Date: Aug 2001
Posts: 2,572
| lol Prelude.... its only a job. One day you will see that.(My missus threatened to leave if I spent any more time coding) Anyway... excellent article OOP. This should make the FAQ thread. In OOP I use structures for POD (thats plain old data), everything else gets put in classes.
__________________ Free the weed!! Class B to class C is not good enough!! And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi |
| Stoned_Coder is offline | |
| | #10 |
| Refugee Join Date: Aug 2001
Posts: 2,052
| OOP, id say that there was more text in that post than in all of my posts put together!
__________________ Please direct all complaints regarding this post to the nearest brick wall Have a nice day. |
| face_master is offline | |
| | #11 | |
| Programming Sex-God Join Date: Nov 2002
Posts: 1,078
| Quote:
Anyways, glad you liked the "article." If a mod wants to put it in the FAQ thread that's fine, but I'd like to add stuff to it first IE pure virtual member functions, virtual destructors, "pure virtual destructors", explicit constructors, operator overloading, and stuff. Maybe more examples too. | |
| Polymorphic OOP is offline | |
| | #12 | |
| Refugee Join Date: Aug 2001
Posts: 2,052
| Quote:
__________________ Please direct all complaints regarding this post to the nearest brick wall Have a nice day. | |
| face_master is offline | |
| | #13 |
| Programming Sex-God Join Date: Nov 2002
Posts: 1,078
| What makes you think I wasn't talking to Sebastiani? ... #endsarcasm |
| Polymorphic OOP is offline | |
| | #14 |
| Registered User Join Date: Jan 2002
Posts: 18
| I can't wait til I get good at programming. Maybe then I'll be able to make a text based chess game since graphics seems to be a pain in C++. For now I think it's on to my text based minesweeper game. OOP - You're my hero
__________________ Be yourself for those who mind don't matter, and those who matter don't mind. |
| motocross95 is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Getting an error with OpenGL: collect2: ld returned 1 exit status | Lorgon Jortle | C++ Programming | 6 | 05-08-2009 08:18 PM |
| Structure vs. Class | bobbelPoP | C++ Programming | 4 | 07-09-2008 09:44 AM |
| Need help to build network class | weeb0 | C++ Programming | 0 | 02-01-2006 11:33 AM |
| Mmk, I give up, lets try your way. (Resource Management) | Shamino | Game Programming | 31 | 01-18-2006 09:54 AM |
| Converting a C structure into a C++ class | deadpoet | C++ Programming | 7 | 01-07-2004 02:06 PM |