Inheritance help

So I am doing some inheritance but whenever I try it I always never really see the point as I can just put the stuff in the base class instead of the child classes, for instance my code below. I don't rerally know what to put in the two child classes. I can never think of what would be specific to that particular thing.

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
#include <iostream>
#include <string>

using namespace std;

class Enemy
{
    public:
        Enemy();

        void SetName(string arg_name)
        {name = arg_name;}

        string GetName()
        {return name;}

        void SetAttackName(string arg_attack_name)
        {attack_name = arg_attack_name;}

        string GetAttackName()
        {return attack_name;}

        void SetHealth(int arg_health)
        {health = arg_health;}

        int GetHealth()
        {return health;}

        void SetAttackPower(int arg_attack_power)
        {attack_power = arg_attack_power;}

        int GetAttackPower()
        {return attack_power;}

    private:
        string name;
        string attack_name;
        int health;
        int attack_power;
};

Enemy::Enemy(): name("Enemy"), attack_name("Attack"), health(100), attack_power(0)
{

}

class Raptor : public Enemy
{
    public:
        Raptor();

    private:

};

class TRex
{
    public:
        Trex();

    private:
        
};

int main()
{


    return 0;
}
Last edited on
Well, what if the Raptor had a special power that the TRex did not. You would put that special power in the child class Raptor. For example, maybe the Raptor is a pack hunter and has a member function that summons help from other Raptors.
Inheritance should be used carefully. Deep trees of inheritance often a sign of bad style. If you can create base class which would suit all needs, that is fine. Actually aggregation or rethinking your design solves need for inheritance.

True power of inheritance comes with virtual functions. Lets say we have an AI class:
1
2
3
4
5
6
7
8
9
class AI
{
    virtual void attack(Unit& target)
    {
        deal_amage(target, damage);
    }
    virtual void on_hit(Unit& attacker) = 0;
    /*...*/
};
It does not do much. It just provides interface for different implementations of AI:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class PassiveAI: public AI
{
    virtual void on_hit(Unit& attacker)
    {
        flee(); 
    }
    /*...*/
};

class AggressiveAI: public AI
{
    virtual void on_hit(Unit& attacker)
    {
        set_enemy(attacker);
        attack(attacker);
    }
    /*...*/
};
Those two classes implements different behavior. And any class needs only to hold reference or [smart]pointer to base AI class and not care about concrete class. You can assign any AI to any unit. Ffor exmple both passive animals and dangerous thugs could just b single enemy class which holds pointer to AI, but get assigned diferent AI. You can even have spell which temporary alters behavior of enemy by switching its AI.

Now even further, suppose we have wolves who should prefer attacking target already attacked by another wolf:
1
2
3
4
5
6
7
8
9
class PackfAI: public AggressiveAI
{
    virtual void attack(Unit& target)
    {
        send_message(EVENT_WOLFATTACK(target));
       AgressiveAI::attack(target);
    }
    /*...*/
};
That is all. We can assign this AI to anyone, for example we decided that unless lead by somebody bandits would have that AI: done, switching is easy and transparent.
hmm, ok I understand better, but some things still confuse me, but its not understanding the code, its just knowing when to make things just one class or make them into derived classes.

So this for example is my code from above but I changed it because this was easier to understand for me, so I have a base character class and a Mage and an Elf. Now if I had several different types of elves would I make child classes for that class of all the different types of elves? or would I just make a variable that holds the types of elves and set it at run time? I am unsure but i'm leaning towards the latter.

Also how do I pass an enum from a class? do I need a pointer?

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <iostream>
#include <string>
#include <vector>
#include <limits>

using namespace std;

class Character
{
    public:
        Character();

        //Get and set name
        void SetName(string arg_name)
        {name = arg_name;}

        string GetName()
        {return name;}

        //Get and set base health
        void SetBaseHealth(int arg_base_health)
        {base_health = arg_base_health;}

        int GetBaseHealth()
        {return base_health;}

        //Get and set inventory
        void SetBackpack(vector<int> arg_backpack)
        {backpack = arg_backpack;}

        vector<int> GetBackpack()
        {return backpack;}

        //Get and set attacks list
        //void SetAttacksList(enum arg_attacks_list)
        //{attacks_list = arg_attacks_list;}

    private:
        string name;
        int base_health;
        vector<int> backpack;
        //enum attacks_list{};
        //enum items{};
};

Character::Character() : name("Class Type"), base_health(100), backpack(5)
{

}

class Mage : public Character
{
    public:
        Mage();

        void SetAttackFireboltDamage(int arg_set_attack_firebolt_damage)
        {attack_firebolt_damage = arg_set_attack_firebolt_damage;}

        int GetAttackFireboltDamage()
        {return attack_firebolt_damage;}

    private:
        const string attack_name_firebolt;
        int attack_firebolt_damage;

};

Mage::Mage() : attack_name_firebolt("Firebolt"), attack_firebolt_damage(15)
{

}

class Elf : public Character
{
    public:
        Elf();

    private:
        
};

Elf::Elf()
{

}

int main()
{
    Mage mage;
    Elf elf;
    int selection = 0;
    string mageName = "";
    string elfName = "";

    cout << "Pick a class" << endl;
    cout << "1) Mage" << endl;
    cout << "2) Elf" << endl;
    cin >> selection;

    if(selection == 1)
    {
        cin.ignore(numeric_limits<int>::max(), '\n');

        cout << "Please enter a name for the Mage" << endl;
        getline(cin, mageName);

        mage.SetName(mageName);

        cout << "\nYour Mage's name is " << mage.GetName() << endl;
    }
    else if(selection == 2)
    {
        cin.ignore(numeric_limits<int>::max(), '\n');

        cout << "Please enter a name for your Elf" << endl;
        getline(cin, elfName);

        elf.SetName(elfName);

        cout << "\nYour Elf's name is " << elf.GetName() << endl;
    }
    else
    {
        cout << "Error" << endl;
    }

    return 0;
}
In your case your elf class is not needed. You would be better with adding "race" string member to your class.
Also your mage class wouldn't be able to be used as baseclass reference/pointer as it contain functions you would be like to access by your player.

Better way is to have your character to store types of attacks in them:
1
2
3
4
5
6
7
8
9
/*Some enums here*/

[code]struct AttackInfo
{
    std::string name;
    attack_type type;
    attack_element element
    int damage;
}


//Prototypes
//Assuming character class has .add_attack() function
Character* mage = new Character();
mage.add_attack({"Spell: fireball", ATT_RANGED, ELM_FIRE, 20});
mage.add_attack({"Hit with a staff", ATT_MELEE, ELM_PHYSICAL, 5});
Character* elf = new Character();
elf.add_attack({"Shoot an arrow", ATT_RANGED, ELM_PHYSICAL, 15});
//...

//Somewhere:
Character* player;
switch(selection)
{
case 1:
player = new Character(*mage);
break;
case 2:
player = new Character(*elf);
break;
//...[/code]
Topic archived. No new replies allowed.