Classes

Pages: 1234
Thanks Disch!

I like to hear this type of stuff. Blunt criticism is good!

Unfortunately I don't know anything about I/O Flies yet. Will read up on it.

I am just playing around with ideas now. So this isn't "the" approach I am taking. Just a avenue to learn.

Volatile Pulse had mentioned that I shouldn't use classes for stats.(first thought derived classes were used like that) I am new to classes and am testing this new "tool" out.

I only have one derived class posted. I have a few set up for each type of weapon. Staff, dagger, sword, etc. I would like them to have unique properties as in a sword has a chance to cause bleeding, a mace can stun, and an axe can dismember. I am learning as I go along.

Thanks again.
Last edited on
Hi SGM3,

Other aspects of class design are the relationships, "Is a", "Has a", and "Uses a".

"Has a" means that there is another class object (or a collection (list or vector etc) of them, ) inside the class. Example a circle has a CentrePoint which is of type 2DPoint. A bank has a collection of accounts.

"Uses a" normally means that a class function or constructor takes an argument which is an object of another class. A circle might use an angle to calc an arc length.

Sometimes you can have 2 or 3 relationships. A circle can be defined by 3 points, so it uses these, and it has a centre point as well.

"Is a" implies inheritance - An orange "is" citrus which "is" Fruit, which "is" Human Food. This would be coded like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class CHumanFood {
protected:
double Weight = 0.0;
double EnergyValue = 0.0;
double FatContent = 0.0;
double Carbs = 0.0;
};
class CFruit public CHumanFood {
protected:
string VarietyName ="";
};
class CCitrus public CFruit  {
protected:
double VitaminC = 0.0;  //Not much imagination here - other things specific to citrus go here as well
};
class COrange public CCitrus {
protected:
//No imagination at all here - put things specific to Oranges here
public:

setValues function
};


protected: is just like private but all the derived classes member functions have access as well.
Now all these member variables are inherited, so if you create a MyOrange object, you can set all the values using your setValues function. E.g you can set the Weight variable for the MyOrange object.

The idea is to look at each class, and decide what variables it will have. Then look for ones that are common and put them as high up in the inheritance tree as possible. The same for functions - this means that you should only write the function once.

The example above can be expanded to include Vegetables and Meat say with similar classes for them.

Another example, going back to geometry, is the circle and the arc.

A circle has a centre point and a radius. An arc has centre point, radius, start angle, end angle say (there are multiple ways to define arcs). So the common things are centre point and radius - these are already in circle, so circle is the base class and arc is the derived class. Arc does not have centre & radius in it because they are inherited. The more general things are the base classes and the more specialised things are derived classes.

So that brings me to constructors & overloading functions.

Here is a simple example of overloaded functions:

In C, we have the following functions:

abs (int)
fabs (float or double)
labs (long)

So we have 3 functions that do the same thing - return the absolute value.

In C++, we have function overloading, so we can do this:

abs(int);
abs(float);
abs(double);
abs(long);

When we call the abs function, the compiler knows which one to use by the type of the arguments. This is a form of abstraction, because we can just use the abs function and not worry about what we send it.

As I understand it, the purpose of a constructor is to initialise member variables. If you want to calculate things, then this should be done in a member function. Constructors can be overloaded too, so you can initialise certain variables, then call a function that does a calculation for that combination of information.

So with an arc there are all these different ways to calculate them: 3 pts on arc, 2 pts and radius, 2 pts and centre pt, plus others. Say our arc is to be stored as above with centre point, radius, start angle, end angle. Instead of writing functions with different names to calc the arc, we can write several overloaded constructors, each one will take it's unique combination of types of arguments, and call a function that does that particular calculation. These function would be overloaded as well (say we call them CalcArc), they would take the same args as the constructors. It would be tempting to just to write the constructors, but the purpose of these is to initialise only.

The arguments do have to be unique combinations of types / numbers of args, otherwise the compiler is not going to know which one to call. So in the cases of 3 pts on arc, and 2 pts and centre pt, there is confusion because they both have 3 args which are all of type 2DPoint. To get around this, derive CentrePt and ArcPt from 2DPoint, so now you have 2 types, which solves that problem. You might have derive other point types to solve all the different combinations.

I hope this will help you to sort out the design of your classes. Remember the difference between Is, Uses,and Has. Don't be confused by Is, and Has a collection of.
Last edited on
Good to hear from you again TheIdeasMan.

Funny to think back when I was struggling with loops, now I'm working with classes! =) Time flies.

Anyways, I have a lot to think about. I was messing around with I/O files.

Is this stupid?

TEXT FILE
1
Name: Short Sword

Damage: 9

Attack Speed: 1.20
Value: 2GP

2
Long Sword
3
Short Sword
4
Heavy Axe
5
Hammer
6
Maul
7
Dagger
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <fstream>


int main()
{
    std :: ifstream dataFile;
    dataFile.open("numbers.txt");
    std :: string output;
    const int counter = 20;
    int loopLimit[counter];

    if(dataFile.is_open())
    {
        std :: cout << "\t\t---------------Weapon Stats---------------" << std :: endl;
        for ( int loopCount = 0; loopCount < counter; ++loopCount)
        {
            std :: getline (dataFile, output);

            if ( output == "1")
            {
                for( int loopCount = 0; loopCount < 7; ++loopCount)
                {
                    std :: getline (dataFile, output);
                    std :: cout << "\t\t" << output << std :: endl;
                }
                break;
            }
        }
        std :: cout << "\t\t------------------------------------------" << std :: endl;
    }
    dataFile.close();

    return 0;
}

TERMINAL OUTPUT
---------------Weapon Stats---------------
Name: Short Sword

Damage: 9

Attack Speed: 1.20
Value: 2GP
------------------------------------------


I am having fun with it. Have yet to look into loading a file into an array.
Funny to think back when I was struggling with loops, now I'm working with classes! =) Time flies.


Wait until you start templates, threads & exceptions. Oh and overloaded operators, virtual and pure virtual functions ! :D

Your example is not silly, but something similar could be used in a slightly different way.

You could read the file, decide what sort of weapon it is, then create a weapon object of that type and call it's constructor with the info from the file.

I think you will need to have a class for each weapon, but you need to design them first - you might be surprised how much can go in the base weapon class. The derived weapon classes need only have things that are specialised for them.

As Disch has quite wisely said, naming of things is important, and not using the name of the class - rather a verb is a very good idea. Also remember that because something is going to hold a different value, doesn't mean that the variable is going in it's own class, rather it will be in the base class and the different value will be assigned once the derived class object is created.

So have a go at designing the classes properly. Write down on paper the names of all the attributes ( member variable names) for each item, remembering not to use the weapon name in the attribute name and use verbs. Once you have done this for several of them, it should become clear which ones are going to be the same for all of them, and which are specialised.

The same goes for functions, try to get as many as possible into the base class, so you don't have to rewrite any of them.

The function Use (you might call it Attack or something) is worth mentioning. So this function applies damage or whatever else it is going to do to the object being attacked. It would be handy to have this in the base class. You can make it a virtual function in the base class which means that it may be redefined in a derived class.

So now you can have a specialised Attack function for each derived class, which carry out the specialised actions for each class. For the normal type weapons (which have the same functionality), don't redefine the function, so it will use the base class one.

The other thing to do is to have a pure virtual function declaration in the base class. Which means that function must be redefined in derived classes that need objects to be created from them.

If you don't provide a pure virtual function definition in a class, that means that you cannot make an object of the class type because it is not complete. Now this is what you want - you could force the creation of one of the derived class objects. If you do this, then trying to create an object of type Weapon will be an error.

The choice of whether to have a virtual or pure virtual function, is a design decision. If all of the derived classes are specialised then just have a pure virtual function. If some of them have things in common then have a virtual function.

There you go - more stuff to think about !!

I think I may have run into a pickle. How could I call a constructor with info from text file?
The code that reads the text file is a string, and the string is multiple lines of text. I'm thinking, I could convert string to a number but that would add a lot more code and doesn't seem relevant to what you are talking about.

" a class for each weapon" - Do you mean have a base class weapon and derived classes of each item?
How could I call a constructor with info from text file?


You would need to extract out all the relevant info, put them into variables, then create the object and initialise it with the variables you have. You can create an object and call it's constructor all in one go by placing the arg list (in parentheses) after the object name. Of course you need to define a constructor that takes those args.

" a class for each weapon" - Do you mean have a base class weapon and derived classes of each item?


Yes.

I have to head out now (It's Friday night here in Melbourne, Australia) so I won't be able to reply until 5 or 6 hours time.

Good luck.
I am going camping at Yellowstone for the weekend.

Luckily I have an android tablet with a basic c++ compiler. Nothing like writing code in the forest.

I will think about this then. For now I must sleep.

Have a good weekend.
I recently watched a fascinating series on the BBC here in the UK about YellowStone- it traced how Yellowstone changes through the seasons.

Nothing like writing code in the forest.


Dude, when I am in the forest, I enjoy the forest. I am happy not to look at a computer or have anything to do with a phone. Enjoy the fresh air and the views and the company you are with. So have a great weekend. (:o=)
@ Guestgulkan - I know the exact series you are talking about. I recorded it. Great stuff.

Great weekend in the "wild". Hopefully you had an enjoyable weekend as well.
I live within 2 hours of Yellowstone. Mountains all around. I enjoy the outdoors everyday. That being said you should be happy to hear I didn't get any coding done. Took a lot of fresh air in. The air is so fresh you smell nothing but the endless surrounding pine trees. I did however, brain storm and read my books.

I have been messing around since I got back. I managed to get something set up that reads and stores each line from the text file in an array. (not sure if this is the way to do it) I'm trying to figure out how I would assign this data to individual constructors to create objects for each set weapon.

The problem ( I think ) is the read data, it is a string, so numbers for damage or attack speed will have to be converted so I may use them in combat. There also is the problem with pulling the right data out according to the weapon.

Below is the what I have to read and store the text file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
    std :: string weapon[8];
    short loop = 0;
    std :: string line;
    std :: ifstream weaponData ( "test.txt" );

    if ( weaponData.is_open() )
    {
        while ( weaponData.good() )
        {
            getline ( weaponData, line );
            weapon[loop] = line;
            loop++;
        }
        weaponData.close();
    }
        else std :: cout << "Unable to locate file." << std :: endl;

    for ( int loop = 0; loop < 8; loop++ )
    {
        std :: cout << weapon[loop] << std :: endl;
    }

    return 0;
}


So far I have a short sword and a long sword. Both have multiple "levels". Bronze, Iron, Steel, Silver, and Glass. Should I make an array[100+] to store all this data? If I do then I have to code the beginning of each item and run a for loop to display the info for how many lines an item has. Plus, I am not sure how to read from a certain point within the stored data. I could print out each line based on it's location in the array as in:

1
2
3
cout << array[0];
cout << array[1]
cout<< array[2]


This doesn't seem efficient.

Maybe I am thinking about this all wrong.
Last edited on
Should I make an array[100+] to store all this data?


You might have to. If you have like 100 types of items then you'll need a large container to store all of that information.

This doesn't seem efficient.


That seems a perfectly good way of doing it to me.
As long as you're not using strings, you don't need getline to read from files. You can simply use the get function. This will put the next piece of information into what ever variable you decide. I also prefer the technique of using the object methods instead of the standard function.

I'd also stay away from creating a large array, a vector might be better in this context. You could even have a variable at the top that'll let the program know how many weapons are in the file altogether.

I also noticed that you're using the std namespace some places, but not others. Why is this?
I don't use using namespace std;. Instead I usestd ::.
It's a way for me to become familiar with what the std contains, through repetition.

I was reading into vectors in one of my books. Vectors seem to be a better route. Given that vectors can grow in size to accommodate the number of elements. (In my case, weapons).

Is it possible to store all the data for one item in on element? Example:
1
2
3
4
5
6
7
8
array[1]

array[0] = Name: Sword
           Damage: 12
           Attack Speed: 1.20
array[1] = Name: Axe
           Damage: 16
           Attack Speed: 1.00

I know that's not proper coding, just an idea. I could do this if they were all on the same line in the text file, but could I have them on multiple lines? So if I were to call the element It would display as so:
Name: Sword
Damage: 12
Attack Speed: 1.20
Yes. That's the idea behind classes. A class now becomes you element type. So, let's say we have this basic Weapon class:
1
2
3
4
5
6
7
class Weapon {
   private:
      std::string mName;
      int mDamage;
      float mSpeed;
   // ...
};


We can create a vector just from that:
std::vector<Weapon> myWeapons;

You can then push_back() weapons, I believe you said you were going the fstream route for getting your list of weapons, so you would create either new objects for each since weapon in there and make sure you delete them once you're done, or create one temp Weapon to hold the data from your weapon file and then push that back as well.

You have a lot of flexibility to do whatever you want in C++. It's about using your mind to get whatever you want to actually happen.
So if I were to call the element It would display as so:
Name: Sword
Damage: 12
Attack Speed: 1.20


To display elements in your own custom way, you'll need to write a function like so:
1
2
3
4
5
6
void print()
{
     cout << "Name: " << name << endl //continued on next line
             << "Damage: " << damage << endl  //continued on next line
             << "Attack Speed: " << atkSpeed << endl;
}


You call it like sword.print();
If you want to be able to just cout << sword << endl; then look into overloading the << operator. Scroll down towards the bottom of the page:
http://www.cprogramming.com/tutorial/operator_overloading.html
Thanks, I will get onto writing some "test" code to see how this all lays out.

I know there is a lot of flexibility with C++. It is a robust language. I have the idea
of what I want to do, just don't know how to code it. But, I am figuring it out.
SGM3,

If it is data about each weapon that you want to store, why not have member variables of the individual weapon classes to hold the data? I don't see the point in storing them in a separate data structure such as an array or vector or whatever.

Both have multiple "levels". Bronze, Iron, Steel, Silver, and Glass


Could this be handled by a member variable called mMaterial? Then you could have a constructor that took this and other args to create a weapon with those attributes.

This all gets back to designing your classes, and thinking about how they will work together.

So your main program could read the file, and have a switch statement that creates a weapon of the right type and calls it's constructor to set it's attributes (ie member variables). Remember you can overload constructors.

HTH

I have been looking at different ways to approach this. But, I don't think I am able to do this just yet. I may have been over ambitious.

I understand what you are talking about, I just don't know how to do it (turn it into code). Especially if I have a set of weapons with a set of base properties and don't create a class for each.
What I mean is, if I have an axe, long sword, short sword, staff, and etc. then I would have to create an object for each. This is where I get lost. I know how to import a text document into an object but how I take the data and insert it into an object for each weapon is boggling.
SGM3,

First you need to design the classes for the weapons as I outlined earlier. Once you have done that it should be easy to create them with info from the file.

So your main program could read the file, and have a switch statement that creates a weapon of the right type and calls it's constructor to set it's attributes (ie member variables). Remember you can overload constructors.


I would like to make sure of one thing: Can you tell us what the difference between a class and an object is?

Especially if I have a set of weapons with a set of base properties and don't create a class for each.


I think you will need a class for each. Check out this simple scenario.

Say you have different weapons - axe, long sword, short sword and staff. Say each one has a property (aka attribute, member variable) called damage. The amount of damage each one can inflict is different.
So a very simple and naive class design could be like this (yours would be more complex):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class CWeapon {
protected:  
const unsigned  mDamage;
public:
unsigned  getDamage();
};

class CAxe public: CWeapon {

};

class CLongSword public: CWeapon {

};

class CShortSword public: CWeapon {

};

class CStaff public: CWeapon {

};


So each of the 4 actual weapons has a mDamage attribute because it is inherited. This is really bare bones - I haven't set any damage values for any of the weapons. Actually I haven't done very much at all!!

Now we need a Monster:

1
2
3
4
5
6
7
8
9
10
11
class CMonster {
private:    //this line not necessary but I put it in anyway
unsigned Health;
public:

bool ReceiveAttack(CWeapon *pWeapon) {
      Health -= pWeapon->getDamage
      return true;
     }

};


The Monster is defenceless and just subtracts the damage from the relevant weapon from it's health.

The argument to the ReceiveAttack function is worth noting. You can see that it is a pointer to the CWeapon class - how does that work when we want to be able to attack with any of our weapons?

The answer is that a pointer to a derived class is a valid pointer to a base class. So if we sent a pointer to CShortSword to the ReceiveAttack function, it does the right thing. This is great because now we don't have to have an overloaded function that covers every type of weapon.

So the upshot of all this is that we need a class for each weapon so we can send them as args to functions. As well as that, I think you would like your weapons to have different abilities.

About what I was saying earlier about not needing a vector of weapons: You would do that if you had an armoury of weapons that were issued to soldiers say. Each weapon could have a "worn" value that is decreased every time it is used in a battle. Having a vector of say 100 weapons of a particular type places a limit on supply. For now though, I think we need some weapons for the hero to use.

What I would like to see you do is a proper class design. If you learn how to do this properly at this early stage it will be a great help later on when things get really complicated. Sorting out classes should become easier with more experience.

I found this was the case with designing tables for relational databases. There is a formal way of doing it, which is what I did at the start. Now I kind of "Just Know" what goes into which table. Although I still check that some technical things are complied with.

I look forward to your reply.


"What I would like to see you do is a proper class design. If you learn how to do this properly at this early stage it will be a great help later on when things get really complicated. Sorting out classes should become easier with more experience."


This is why I ask a lot of questions and sometimes require things to be spelled out. I appreciate your time to help.

An object is a variable of the class. Eg. int x; Int would be the class while "x" is the object.

This helps a lot. I was trying to figure out a way to import the file through the constructor while passing each set of data to variables for each weapon. I thought having a class for each weapon was wrong, unless they had unique properties. (a mace has a crushing blow) So I wasn't thinking of passing the data to derived classes.

Would I create a getDamage member in the base class and call it in the derived classes?

A question on compiler class set up. I use Code::Blocks, it creates a .h (header file) but it also creates a .cpp file with the class that contains a constructor and destructor. Should I use this? Why does it create the two?

** Not sure why it posted really wide.
Last edited on
Pages: 1234