Failure to Grasp the point of Inheritance

Started by
16 comments, last by LorenzoGatti 16 years, 9 months ago
Alright, is this the right way to use inheritance?

class Manager
{
    public:
    Manager();
    virtual ~Manager();
    virtual void Add() = 0;
    virtual void Release() = 0;
    virtual void Get() = 0;
};

class TextureManager : public Manager
{
    public:
    std::map<std::string, Texture> Textures;
    void AddTexture(std::string Name, std::string Filename);
    void ReleaseTexture(std::string Name);
    GLuint GetTexture(std::string Name);
};

class ModelManager : public Manager
{
    public:
    std::map<std::string, Model> Models;
    void AddModel(std::string Name, std::string Filename);
    void ReleaseModel(std::string Name);
    Model GetModel(std::string Name);
};

If so, what is the advantage(if there is one) of doing this? I have read so very many articles about C++ Inheritance and Polymorphism, but I am just not grasping the concept. Thanks
Advertisement
Niddles, say that I want to hold a list of all the animals that exist in my household. I have two Cats and a Dog, each defined with its own class. Dogs can bark(), Cats meow() -- but they both sleep() and run() and walk(). By creating a parent class, Animal, which they both inherit from, they both inherit all the actions of an Animal, and then extend the class with their own abilities. Theoretically, I could implement sleep(), run(), and walk() in my Cat and Dog classes, but there is too much code overlap. They share the methods, and therefore should get them from a common base.

Not only that, but now I can generalize my Cats and Dogs as Animals and hold them in any sort of container I want (remember, containers have a type associated) and access any of the methods an Animal has! I can walk() all my pets at once now because my Animal class gaurantees that the method is implemented (even if it is pure virtual)!
Alright, I'm not even going to really look at the code, but as a programmer, inheritance among classes is critical to understand. Let's say that you are making a game where you have to make a class for each animal that is going to be on the screen, and there could be anywhere from ten to fifty different kinds of animals depending on what the designer wants. So, instead of making fifty independent classes, it'd be very, very much quicker and easier to make one CAnimal class that defines things that each of the animals have (age, etc.) and some of the things all of them do (eat(), sleep(), etc.). Now that you have CAnimal, you can make things like CDog and CCat and CMoose derive from CAnimal and not only will you be able to add or remove any animal class much, much faster, but also you can change/add/remove variables/functions that each of the animals will need just by changing CAnimal.

I don't know if I wrote that up easy enough to understand, but I"m sure someone on GDNet will.
=============================All knowledge is good; only the way it is put to use is good or evil.
Okay so rather than making 50 independent classes, you have 1 base class, and then have 50 classes inherit from that... See? I just don't see the point.
... Because then all the values those classes inherit can be changed within a snap by changing the base class. Plus the base class defines values and functions that would be in each of them if they didn't inherit it so it makes writing those classes a LOT faster.
=============================All knowledge is good; only the way it is put to use is good or evil.
Quote:
Original post by Niddles
Okay so rather than making 50 independent classes, you have 1 base class, and then have 50 classes inherit from that... See? I just don't see the point.


But that base class has some functionality that all animals use. By inheriting from Animal, you only need to implement this functionality once (in Animal). The derived classes only need to implement their specific behavior.
Alright, so the point is to make it easier on the programmer?
Yes, one reason is code reuse. Another is polymorphism.
The purpose of inheritance is to reuse the code and to save you a bunch of work.

Lets say we are making an RPG. We will think about how inheritance helps us.

Our world is made up of objects but many different types of objects. So we think about what all of our objects have in common.
Object; name, texture, model.

Now we have two type of objects; static and non-static.
Non-Static; location, weight, size (and the characteristics of Object)

Now non-static has some types; World objects, usable objects.

And we continue, all the way down to Sword, Potion, Armor. ect.

So how does that help us?

Well object takes care of the name, texture and model. Every object that is inherited from that gets all of those part without having to write that code in.

Usable objects gets location, weight and size from non-static objects, and name, texture and model from object.

Once you get the base classes solid then it will be correct for every class that inherits it. If you need to change the type of model you are using for the whole game, you just go in to base class object, and change the code for models, and then the whole game is changed. If you change your coordinate system you just go in and change the location parts and it is all done. You don't have to go through all your classes to make the change, just the base class.

theTroll
If you don't see a use for it, don't try for it. Chances are you're right, honestly.

Good uses of inheritance will stand out: you'll see similarities between things and think "there must be a way I can reuse that".

As for your code example: you can't "rename" a virtual function in the derived class; the compiler would have no way of knowing what should be mapped to which. So in TextureManager, for example, it should not be "AddTexture" but just "Add". This is also good practice for identifier naming anyway: avoid putting (part of) the class name into a member name, because it doesn't communicate any more information. It's like saying you're putting a letter stamp on your letter before you mailbox-drop it into the mailbox.

Also, you can't change the return type, except in very limited ways ([google] "covariant return types"). And you can't change the parameters, either. Well, you can, but then you're not actually implementing the virtual function, but just adding another one that happens to have the same name.

Besides that, though, there are other things you have to worry about if you try to use those classes polymorphically (in particular, copy construction and assignment are likely to be problematic, and you may need to make use of the "virtual clone idiom"). Not that there's a point to doing it for manager classes - unless you have a "manager manager" somewhere that runs over all the managers.

In the case of these manager classes, what you probably really want to do is use templates instead:

template <typename T>class Manager {  std::map<std::string, T> things;  public:  // Probably no need for a constructor or destructor.  // But please, pass objects by const reference.  void Add(const std::string& Name, const std::string& Filename);  void Release(const std::string& Name);  // With templates, we can "fill in the blank" for the return type here.  // Nothing interesting fnord here, move along.  T Get(const std::string& Name);};typedef Manager<Texture> TextureManager;typedef Manager<Model> ModelManager;


Anyway, there's a lot to read about when it comes to inheritance (1 2 3 4 5 6 7). Have fun :)

[Edited by - Zahlman on July 27, 2007 12:33:17 AM]

This topic is closed to new replies.

Advertisement