Inheritance - 2 Classes - Questions

I am trying to learn more by practicing doing simple exercises on classes.

- I have made a Player class which is player.h and player.cpp.
- I have made Enemy class which is enemy.h and enemy.cpp.

- Player class have private members called int health and int ammo.



What I’m trying to do or learn is make the Enemy class also have members int health and int ammo via inheritance. Though the members are private in Player class - Can someone show me how without making members public? If there are many different ways of doing this please show.


Thanks.






There are two ways:

1) Make the data members in the base class protected instead of private.

2) Have accessor functions for those data mambers in the base class, and have the derived class call those functions.

The first option is more convenient, but many would argue it violates the principle of encapsulation,

The second option is more strict about encapsulation.
@MikeyBoy has you covered on the facts.

Stroustrup writes that the protected protection level should probably not be used (I paraphrase of course).

What I wanted to append is prompted by this:

"...make the Enemy class also have members int health and int ammo via inheritance."

Certainly we do, when members are public, consider the members a part of the derived class, as if creating a composite object. There are advantages, simplicity being primary.

However, that construction promotes the habit that each of the derived classes then operate upon those members, instead of the base class (which holds those declarations). This leads to duplication of functions where the overall operation and use of these members is the same. Of course, personal discipline could move such duplicate functions in the derived classes into the base, to eliminate the redundancy.

However, making the members in that base private stops any attempt to write functions which operate the base members. That makes redundant code impossible in that context, but it does then prompt the creation of "getters and setters", which then all but eliminate the privacy of those members. If the base class first makes member data private, but then provides complete access to them through getters and setters, there is hardly any actual protection. The only exception to that is the fact that all usage must go through the "get and set" functions, which offers some opportunity to enforce limits on the values, or other usage discipline.

That still implies that the derived classes are performing the work on these concepts. That may be limited, fortunately, where the "get" functions might be used merely to display, and "set" might have controls to limit the values assigned, but this may miss an important opportunity, and avoids one of the powers of having objects in the first place.

I've replied to you on this same question previously, and you've moved in the direction that discussion suggested, but now you're exploring that second phase everyone who studies this for the first time must confront.

These two notions, health and ammo, are entirely unrelated. Ammo is a quantity, I presume, which represents what the player possesses. Health, on the other hand, is something more fundamental to the player. This is a measure of the condition of the player, and it could expand considerably over the evolution of your work. Ammo could expand, as a concept, too. It is important to understand how such evolution is likely to impact your object design. It informs as to how to implement on the very point you're raising.

First, health as a single number may work in simple situations just fine. However, you may, at some point, prefer to express health in terms of certain details. Missing limbs, for example, differ in their impact on health than, say, dehydration or poisoning. An overall health value says little about how the player might recover from a poor health condition. It isn't likely a player is going to grow a new arm or leg, for example.

Ammo may well be considered a count of bullets, but what kind? How many weapons that use ammo might be in play? Is ammo considered universal? I would expect that ammo may evolve to a quantity suitable for particular weapons, over time.

If these values were treated merely as a number in the base "player" class, but operated by the derived "enemy" class, then if the meaning of ammo or health were to change in the future, that work might require duplication in other derivative classes of "player".

If, instead, all operation of these members is in the player class, then all changes made to the meaning of these values are limited, if done correctly, to code in the player class. The concepts could evolve more painlessly (to the programmer).

This is ultimately the reason for making these values private, but that misses the associated important concept. It isn't enough.

All interface to the concepts of health and ammo should be performed as interfaces in the player base class.

Ammo implies the possession of weapon, which implies the firing of a weapon. These are both notions that should be implemented with functions in player (and likely some of them private functions). The player should provide a simple, clear interface for the use of the weapon. Perhaps "aim" and a "fire" functions. Those functions would then consume the ammo, and would likely communicate that a bullet (or whatever ammo represents) has been fired, and if it hits a character informs that character it has been hit (and possibly where), by a "player to player" interface.

When a player receives notice that it has been hit, the impact likely detracts from health. That might evolve into damage to limbs vs the torso. Other forms of damage might impact health differently, like disorientation from dehydration, poisoning or exhaustion.

Notice that none of that involves the "enemy" derivative.

...and, it would, therefore, work the same way for any other derivative of player.

When the moment comes to display the ammo remaining, it is the player, not the enemy, that displays that value. Similarly, where a display of the health value is required, it is the player, not the enemy, that displays the health value.

In none of that did the enemy require access to these private values.

Instead, public functions in player constitute an interface representing how these concepts are implemented, and therefore operate the same for all derivatives of the player class.

This is how you should be thinking.

More generally, imagine that the player base class is a small electronic device you've built. It has a box with a face. On that face may be dials, buttons, sliders and displays (showing values). There might be connectors to plug into.

However, what is inside the box is never seen, and the user of that device shouldn't have to look inside to use it. Only that which is intentionally put on the face of the box is used by the consumer of this device.

Whatever manipulations the user might perform on the buttons, dials and sliders, or what values they might read from the display, that is all they have to operate the device, and it should be everything they need. This is the public interface, usually as a collection of public functions.

Everything else is inside the box. These are the private data and functions internal to the device. That may be larger in content than what is shown. Your phone, for example, has a touch input, a display, audio output, audio input, a few "unseen" yet still public interface devices, like GPS and the accelerometer. That's a handful of public interfaces.

However, there are billions of transistors, gigabytes of RAM and storage inside, that you consume but never touch.

This is how you should be thinking in the design of classes. You are making a machine out of logic and language, not a collection of functions or instructions.


Last edited on
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
#include <iostream>

struct properties // properties common to more than one class
{
    int health ;
    int ammo ;
};

class player : private properties // inherit privately
{
    public:
        player( int initial_health, int initial_ammo )
            : properties{ initial_health, initial_ammo } {}

        // members of player can access inherited health and ammo (though others can't)
        long long wellbeing() const { return health * ammo ; }

    // etc.
};

class enemy : private properties // inherit privately
{
    public:
        enemy( int initial_health, int initial_ammo )
            : properties{ initial_health, initial_ammo } {}

        // members of enemy can access inherited health and ammo (though others can't)
        long long viciousness() const { return health * ammo ; }

    // etc.
};

int main()
{
    player p( 11, 8 ) ;
    std::cout << p.wellbeing() << '\n' ; // fine
    // p.health ; // *** error: private base class

    enemy e( 4, 18 ) ;
    std::cout << e.viciousness() << '\n' ; // fine
    // e.ammo ; // *** error: private base class
}
Topic archived. No new replies allowed.