Why do we study classes and objects?

Pages: 123
Dont just jump on concepts unnecessarily without understanding why you should adopt them.


Okay :)
Until i understand why I should switch to something I dont switch.


When i began to feel to much irritation, I switched to functions...and now i cant live without them.


Dont just jump on concepts unnecessarily without understanding why you should adopt them.


Translation : So until I learn what C++ is I won't use C++ until I have a reason to use C++?


EDIT:

Oh, and by the way.

I bet my life savings that you can't live without functions now because you growed a pair of balls and used them.

Then when we used them, you understood the power and control they give you.


Now do the same with classes and objects, and soon enough, you won't be able to code without them.
Last edited on
Also keep in mind that C++ is similar to python in the respect that neither language forces you to code with an OOP paradigm. You can do anything you want sticking with pure procedural programming so technically you'll never have a reason to use OOP unless you choose to learn it in order to leverage its power.

Don't make yourself use it if you're not ready but that's no excuse not to start playing around with the concepts. It's too powerful to dismiss but take your time with it as you will find that you need to play around for quite a while until that AHA! moment comes along.
I bet my life savings that you can't live without functions now because you growed a pair of balls and used them

You're true about that.

Don't make yourself use it if you're not ready but that's no excuse not to start playing around with the concepts. It's too powerful to dismiss but take your time with it as you will find that you need to play around for quite a while until that AHA! moment comes along.

I get it. I guess you guys make sense. :k
So, to conclude:
I wont be able to understand and appreciate OOP until I use it.
That is correct, you're making progress.

You could watch a video on youtube, for instance "How to make the perfect apple pie".

It gives you exact ingredients from the shop and the exact measurements down to a long double, but when you go to cook it, even when following instructions you will mess it up, because there is no "perfect" in this world, there is no linear one size fits all.


Here is a test, to try and wrap your head around OOP:


Make a "Weapon" class that contains a name, damage and value.

The attributes are set in the constructor, and the data cannot be modified once the class is created ( We don't want people changing the damage or value now, do we? ) However the class can return the value of the attributes.

Make 3 "Weapons".

Next make a "Player" class that contains name and gold coins. Make sure the gold coins cannot be directly accessed, and the only want to change it is with a "Buy(unsigned int value)" function, which takes the item value away from the Player gold coins.

Make a "Shop" function in which then the player can choose the buy one of the three weapons, and the gold is deducted from the Player gold coins.


Let's see what you come up with.
The attributes are set in the constructor, and the data cannot be modified once the class is created ( We don't want people changing the damage or value now, do we? )


But, with constructors I can initialise the attributes of the 3 weapons to the same value right.
if I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
class weapon
{
string name;
int value,damage;
public:
weapon();
}
weapon::weapon()
{
name = "Sword";
value = 85;
damage = 14;
}


Now, when the weapon 1, weapon 2 and weapon 3 are created they will be initialised to this(name = sword; value = 85; damage = 14) right? Then, why should I use a constructor at all.
If I dont want the data to be changed after creation cant I just use a const before it?
Last edited on
Oh...I got what you meant. Wait a sec.
Default constructor is meaningless in this case.
If I dont want the data to be changed after creation cant I just use a const before it?
Sometimes you do not want somebody to change arbitrary data (for example basic sword dealing over 900 damage or endgame lazer rifle cost 1 gold), but do want to change weapon itself: swap(equipped_weapon, weapon_in_backpack)

Usually this approach is fueled by usage of flyweight or prototype patterns.
I said:

set in the constructor


Very bad English on my part ( and I live here ).

I meant in the constructor arguments:

 
Weapon(std::string name, unsigned int dmg, unsigned int val): w_name(name), w_dmg(dmg), w_val(val) {}
megatron 0,
I dont know how the two classes can share their private members. Man, I am sooo tired. Is this friend thing right?
Please help me. I know my code is messy but Its my first time with classes which fumble with each others private members.lol.

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>

using namespace std;

void shop();


// Weapon Class Definition
class weapon
{
    string name;
    int cost,damage;
public:
    weapon();
    void display();
    friend void buy();
    
    
};

// Weapon Objects
weapon wp1,wp2,wp3;


// Weapon Constructor
weapon::weapon()
{
    wp1.name = "ShotGun";
    wp1.cost = 700;
    wp1.damage = 93;
    
    
    wp2.name = "Rifle";
    wp2.cost = 960;
    wp2.damage = 120;
    
    
    wp3.name = "Laser-Rifle";
    wp3.cost = 1400;
    wp2.damage = 175;
}

void weapon::display()
{
    cout << "Name: " << name << endl;
    cout << "Cost: " << cost << endl;
    cout << "Damage: " << damage << endl;
    
    cout << "To buy press 'b'" << endl;
    cout << "To go back press 'q'" << endl;
    
    char choice;
    cin >> choice;
    switch(choice)
    {
        case 'b': break;
        case 'q': shop(); break;
        default: display(); break;
    }
}



// Player Class Definition
class player
{
    string name;
    int coins;
public:
    void shop();
    friend void buy();
    
    
}p1;


void buy()
{
    coins = coins - cost;
    
    
}

void player::shop()
{
    cout << "To view details of ShotGun, Press 1" << endl;
    cout << "To view details of Rifle, Press 2" << endl;
    cout << "To view details of Laser-Rifle, Press 3" << endl;
    
    int choice;
    cin >> choice;
    
    switch(choice)
    {
        case 1: wp1.display(); break;
        case 2: wp2.display(); break;
        case 3: wp3.display(); break;
        default: shop(); break;
    }

}


int main()
{
    shop();
}





Ill update the code by tomm.
Dont help.
:)
Do not use friends. Your use of this is even more of an indication that you should be using/learning encapsulation.

I dont know how the two classes can share their private members.


Here's an example:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>

class MyClass
{
private:
	int m_private1;
public:

	void setPrivateVariable(int x)
	{
		m_private1 = x;
	}

	int getPrivateVariable()
	{
		return m_private1;
	}
};

class YourClass
{
private:
	MyClass m_MyClass;

public:

	YourClass(MyClass& myclass)
	{
		m_MyClass = myclass;
	}

	void displayVariableFromOtherClass()
	{
		std::cout << m_MyClass.getPrivateVariable() << std::endl;
	}
};



int main()
{
	MyClass myclass;
	myclass.setPrivateVariable(42);

	YourClass yourClass(myclass);
	yourClass.displayVariableFromOtherClass();

	return 0;
}
Last edited on
Also you should not use global variables here either, you have undefined behavior as you assigning values to not yet created objects (static order initialisation fiasco, another danger of globals).

Weapons should not have code related to shop (buying). Also there is serious problem with extensibility: What if you need several different shops? What if shops should update their invertory depending on time or what you have already bought? What if I add 30 kinds of weapons tomorrow?

Slight rewrite, it does not truly support everything I said, but additional functionality can be added without rewriting existing code:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

// Weapon Class Definition
class Weapon
{
public:
    std::string name() const
    { return name_m; };

    int damage() const
    { return damage_m; }

    int cost() const
    { return cost_m; }

    void display() const;

    static Weapon create(const std::string& weapon);
private:
    Weapon(std::string name_, int cost_, int damage_)
        : name_m(name_), cost_m(cost_), damage_m(damage_) {}
    std::string name_m;
    int cost_m;
    int damage_m;
};


void Weapon::display() const
{
    std::cout << "Name:   " << name()   << '\n' <<
                 "Cost:   " << cost()   << '\n' <<
                 "Damage: " << damage() << '\n';
}  


Weapon Weapon::create(const std::string& weapon)
{
    static std::unordered_map<std::string, Weapon> weapons = { {"shotgun", {"ShotGun", 700, 93}},
        {"rifle", {"Rifle", 960, 120}}, {"laser_rifle", {"Laser-Rifle", 1400, 175}},
    };
    return weapons.at(weapon); //Throws exceptions if tried to create unknown weapon
}

class Shop
{
public:
    Shop();
    void stock() const;
    void info(std::size_t index) const;
    Weapon buy(std::size_t index);
private:
    std::vector<Weapon> goods;
};

Shop::Shop()
    : goods( {Weapon::create("shotgun"), Weapon::create("rifle"),
              Weapon::create("laser_rifle") })  {}

void Shop::stock() const
{
    for(int i = 0; i < goods.size(); ++i)
        std::cout << i + 1 << ": " << goods[i].name() << '\n';
}

void Shop::info(std::size_t index) const
{
    goods.at(index).display();
}

Weapon Shop::buy(std::size_t index)
{
    return goods.at(index);
}


// Player Class Definition
class player
{
    std::string name;
    int coins;
public:
    void shop(Shop& where);
};


void player::shop(Shop& where)
{
    while (std::cin) {
        std::cout << "Enter 0 to exit or choose something to get extra information:\n";
        where.stock();
        int choice;
        std::cin >> choice;
        if (choice == 0)
            break;
        where.info(--choice);
        std::cout << "Do you want to buy? (Y/N)\n";
        char ans;
        std::cin >> ans;
        if (ans == 'Y')
            coins -= where.buy(choice).cost();
    }
}


int main()
{
    Shop generic_shop;
    player red_player;
    red_player.shop(generic_shop);
}
Last edited on
@MiiNiPaa

I'd wrap if statements around your input too, to reset cin if they try inputting a string into an int and fall in a loop. I know you know this, I was wondering why you didn't incorporate it?
Original code didn't do that either and I di not want to overcomplicate it. It is already barely resembles original.

Also I do not have proper exception handling, some static function variable should be class members, Shop does not have proper constructors/manipulation functions, but it all can be easily added without changing original code structure.
@MiiNiPaa I dont understand "a lot" of your code. You must be really advanced.

In,

class player
{
std::string name;
int coins;
public:
void shop(Shop& where);
};

what is (Shop& where)?
@mutexe,
Why should I not use friend function?
what is (Shop& where)?
Instance of players takes Shop instance by reference (Where he will be shopping). Pass by reference is needed to avoid copy and to be able to change Shop object (in future it would make sense to remove bought veapon from shop).
http://www.learncpp.com/cpp-tutorial/611-references/
http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/

You must be really advanced.
Most code is pretty basic and just follows basic programming rules: const correctness, encapsulation, one responcibility principle...
Only advanced thing is Weapon::create function which implements Prototype and Factory Method patterns and using map container (which is pretty useful actually).

Why should I not use friend function?
For same reason why you should not expose implementation by just anybody. Imagine the future when different classew will be implemented in different classes and code will become more complex. And now imagine that you want drop variable coins and track different types of coins independenly.
Properly encapsulated class will just change members and will fix get_money() member function to return sum of all coins. For improperly encapsulated class you now need to track and fix all usage of old coins variable. Even worse if it will be repurposed for something else because all function which depended on it will work improperly.

Generally only functions/classes which logically part of the class but physically cannot be should be friends. For example operator<< for stream output or swap() function enjoying argument-dependend lookup.
When I read about passing arguments by reference I really didn't think of it as that important. I never really thought it could be used as a alias.

Thanks for the links as well.

I also didnt understand this:
Megatron 0 said:
We don't want people changing the damage or value now, do we?


Now, If i am going to give the compiled program to my customer(whos gonna play the game). Then, he wont have access to the source code right?
Then how can he change the damage or other data values?


Pages: 123