How should a basic class hierarchy be constructed?

Skamah One picture Skamah One · Apr 21, 2013 · Viewed 19.1k times · Source

I know how to code and use simple classes, and I even know how inheritance works and how to use it. However, there's a very limited amount of guides on how to actually design the structure of your class hierarchy, or even how to design a simple class? Also, when and why should I inherit (or use) a class?

So I'm not really asking about how, I'm asking when and why. Example codes are always a good way to learn, so I would appreciate them. Also, emphasize the progress of designing rather than simply giving one sentence on when and why.

I program mainly in C++, C# and Python, but I'll probably understand the simple examples in most languages.

If any of the terms seem mixed up or so, feel free to edit my question. I'm not a native and I'm not sure of all the words.

Answer

user2032433 picture user2032433 · Apr 21, 2013

I'll use C++ as an example language, since it relies so much on inheritance and classes. Here's a simple guide on how to build controls for a simple OS, such as windows. Controls include simple objects on your windows, such as buttons, sliders, textboxes, etc.


Building a basic class.

This part of the guide applies for (almost) any class. Remember, well planned is half done. What kind of class are we working on? Which are it's attributes and what methods does it need? These are the main questions we need to think of.

We're working on OS controls here, so let's begin with a simple class, shall it be Button. Now, what are the attributes on our button? Obviously it needs a position on the window. Also, we don't want every button to be exact same size, so size is an other attribute. Button also "needs" a label (the text drawn on the button). This is what you do with each class, you design it and then code it. Now I know which attributes I need, so lets build the class.

class Button
{
    private:
        Point m_position;
        Size m_size;
        std::string m_label;
}

Notice how I've left out all the getters and setter and other methods for the sake of shorter code, but you'd have to include those too. I'm also expecting us to have Point and Size classes, normally we'd have to struct them ourselves.


Moving onto the next class.

Now that we got one class (Button) finished, we can move to the next class. Let's go with Slider, the bar which e.g. helps you scroll web pages up and down.

Let's begin like we did on button, what does our slider class need? It's got location (position) on the window and size of the slider. Also, it's got minimum and maximum values (minimum means that the scroller is set to the top of the slider, and maximum means it's on the bottom). We also need the current value, i.e. where the scroller is at the moment. This is enough for now, we can build our class:

class Slider
{
    private:
        Point m_position;
        Size m_size;
        int m_minValue;
        int m_maxValue;
        int m_currentValue;
}

Creating a base class.

Now that we got two classes, the first thing we notice is we just defined Point m_position; and Size m_size; attributes on both classes. This means we have two classes with common elements and we just wrote the same code twice, wouldn't it be awesome if we could write the code only once and tell both of our classes to use that code instead of rewriting? Well, we can.

Creating a base class is "always" (there are exceptions, but beginners shouldn't worry about them) recommended if we have two similar classes with common attributes, in this case Button and Slider. They are both controls on our OS with size and position. From this we get a new class, called Control:

class Control
{
    private:
        Point m_position;
        Size m_size;
}

Inheriting similar classes from common base class.

Now that we got our Control class, which includes the common items for every control, we can tell our Button and Slider to inherit from it. This will save us time, computer's memory and eventually time. Here's our new classes:

class Control
{
    private:
        Point m_position;
        Size m_size;
}

class Button : public Control
{
    private:
        std::string m_label
}

class Slider : public Control
{
    private:
        int m_minValue;
        int m_maxValue;
        int m_currentValue;
}

Now some people might say that writing Point m_position; Size m_size; twice is much easier than writing twice : public Control and creating the Control class. This might be true in some cases, but it's still recommended not to write the same code twice, especially not when creating classes.

Besides, who knows how many common attributes we'll eventually find. Later on we might realize we need Control* m_parent member to the Control class, which points to the window (or panel or such) in which our control is held in.

An other thing is, if we later on realize that on top of Slider and Button we also need TextBox, we can just create a textbox control by saying class TextBox : public Control { ... } and only write the textbox specific member variables, instead of size, position and parent again and again on every class.


Final thoughts.

Basically always when you have two classes with common attributes or methods, you should create a base class. This is the basic rule, but you are allowed to use your own brain since there might be some exceptions.

I am not a professional coder myself either, but I'm learning and I've taught you everything as my educators have taught it to me. I hope you (or atleast someone) will find this answer useful. And even though some people say that python and other duck typing languages don't even need to use inheritance, they're wrong. Using inheritance will save you so much time and money on larger projects, and eventually you'll thank yourself for creating the base classes. The reusability and management of your project will become billion times easier.