C Board  

Go Back   C Board > General Programming Boards > C++ Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 12-01-2002, 03:33 PM   #1
Registered User
 
Join Date: Dec 2002
Posts: 1
Post structure vs class

Please tell me the basic difference between structure of "c language" and class of "object oriented programming".
sana is offline   Reply With Quote
Old 12-01-2002, 03:37 PM   #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   Reply With Quote
Old 12-01-2002, 07:27 PM   #3
Programming Sex-God
 
Polymorphic OOP's Avatar
 
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
};
I left out the implementation for simplicity, and as you can see, the array can't do much right now. You can't even access any indices in the array yet!

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
Player MyPlayer = { 100, 50 }; // Initialize CurrentHealth to 1 and CurrentArmor to 50

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;
};
Again, I'm leaving out the implementaton of the function, but I'll get back to it in a second.

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;
}
So now, you can, for instance do

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 );
Well, in C++, since the "Attacker" parameter is implicit, you have to specify this elsewhere. So, you put the word "const" after the function name and parameter list. Look back to the GetHealth funciton for an example of this.

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++
}
So, with that code, we can now do:

Code:
int main()
{
    IntArray( 5 ); // Make an array of length 5
    return 0;
}
This will create an array of length 5, and then, when main is finished, the destructor will get called and deallocate the memory!

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
{
};
Before going any further, just think about the concept.

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!
We have just discovered that a pointer to an enemy can now point to a big enemy OR a small enemy as well!!! That means anythime we have a function that takes as a parameter a pointer to an enemy, we can pass a pointer to a small enemy or a big enemy as will! You've just made your game quite a bit more modular!

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
}
Also, notice the "public" when used with the inheritance itself -- I'll touch on that in a bit.

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;
}
That test didn't go over too well... but don't be discouraged!!! There actually is a way to do what you want, and all you have to do is use one simple little word.

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;
}
Great!!! We now have a way of thinking about all the different kinds of enemies as "enemies," can store them on like terms, and be able to use varying versions of functions on them!!!

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
{
};
Multiple inheritance gives a lot of power, and it's most oftened not used to directly mean a MiniVan is both a Car and a Van, but rather, to just combine two different implementations.

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
{
};
Now:

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   Reply With Quote
Old 12-01-2002, 08:03 PM   #4
¡Amo fútbol!
 
Join Date: Dec 2001
Posts: 2,121
Buddy, have a little time on your hands?
golfinguy4 is offline   Reply With Quote
Old 12-01-2002, 08:11 PM   #5
Programming Sex-God
 
Polymorphic OOP's Avatar
 
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   Reply With Quote
Old 12-01-2002, 08:41 PM   #6
Guest
 
Sebastiani's Avatar
 
Join Date: Aug 2001
Posts: 4,923

Dedication. Devotion. Great attitude.
Sebastiani is offline   Reply With Quote
Old 12-01-2002, 11:17 PM   #7
Code Goddess
 
Prelude's Avatar
 
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   Reply With Quote
Old 12-01-2002, 11:46 PM   #8
Programming Sex-God
 
Polymorphic OOP's Avatar
 
Join Date: Nov 2002
Posts: 1,078
Marry me
Polymorphic OOP is offline   Reply With Quote
Old 12-02-2002, 12:22 AM   #9
Skunkmeister
 
Stoned_Coder's Avatar
 
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   Reply With Quote
Old 12-02-2002, 12:26 AM   #10
Refugee
 
face_master's Avatar
 
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   Reply With Quote
Old 12-02-2002, 12:34 AM   #11
Programming Sex-God
 
Polymorphic OOP's Avatar
 
Join Date: Nov 2002
Posts: 1,078
Quote:
Originally posted by Stoned_Coder
its only a job. One day you will see that.
No way!!! Coding is an art and a way of life! Grrrr

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   Reply With Quote
Old 12-02-2002, 12:36 AM   #12
Refugee
 
face_master's Avatar
 
Join Date: Aug 2001
Posts: 2,052
Quote:
Originally posted by Polymorphic OOP
Marry me
::Slowly steps back towards the door, waiting for Prelude to pull out her revolver::
__________________
Please direct all complaints regarding this post to the nearest brick wall Have a nice day.
face_master is offline   Reply With Quote
Old 12-02-2002, 12:38 AM   #13
Programming Sex-God
 
Polymorphic OOP's Avatar
 
Join Date: Nov 2002
Posts: 1,078
What makes you think I wasn't talking to Sebastiani?


...


#endsarcasm
Polymorphic OOP is offline   Reply With Quote
Old 12-02-2002, 07:18 AM   #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   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

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


All times are GMT -6. The time now is 07:20 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22