Thread: structure vs class

  1. #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".

  2. #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.

  3. #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.

  4. #4
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    Buddy, have a little time on your hands?

  5. #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!

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708

    Dedication. Devotion. Great attitude.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >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.

  8. #8
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    Marry me

  9. #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

  10. #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!

  11. #11
    Programming Sex-God Polymorphic OOP's Avatar
    Join Date
    Nov 2002
    Posts
    1,078
    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.

  12. #12
    Refugee face_master's Avatar
    Join Date
    Aug 2001
    Posts
    2,052
    Originally posted by Polymorphic OOP
    Marry me
    ::Slowly steps back towards the door, waiting for Prelude to pull out her revolver::

  13. #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

  14. #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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Structure vs. Class
    By bobbelPoP in forum C++ Programming
    Replies: 4
    Last Post: 07-09-2008, 09:44 AM
  3. Need help to build network class
    By weeb0 in forum C++ Programming
    Replies: 0
    Last Post: 02-01-2006, 11:33 AM
  4. Mmk, I give up, lets try your way. (Resource Management)
    By Shamino in forum Game Programming
    Replies: 31
    Last Post: 01-18-2006, 09:54 AM
  5. Converting a C structure into a C++ class
    By deadpoet in forum C++ Programming
    Replies: 7
    Last Post: 01-07-2004, 02:06 PM