profile image

C++ Virtual Class Inheritance

March 11 2010

Virtual Class Inheritance is something some of us have a difficult time wrapping their heads around initially. It can be a useful tool, so I’m going to try to explain it a little bit here.

Let’s suppose we have a Garden with different kinds of plants growing in it (how original.) We can start out by creating a very general class called Plant. With generalization in mind, we can only specify attributes and functions that all plants share.

class Plant
{
public:
  virtual ~Plant();
  virtual Plant* clone() const = 0;

  string getColor() const
  {
    return color;
  }

  int getHeight() const
  {
    return height;
  }

  void grow(int n)
  {
    height = height + n;
  }

  virtual bool isRipe() const = 0;

protected:
  string color;
  int height; //inches
};

You’ll notice that the isRipe() function has the keyword “virtual” next to it, and it’s set to equal 0. This defines a virtual function that is not defined in the base class. There is no way of knowing whether a plant is ripe without knowing what kind of plant it is. So we will define this function in the sub-classes.

You should also notice that the destructor is virtual. This is because there may be additional private members in the sub classes that this base class doesn’t know about. Not declaring the destructor as virtual would likely lead to memory leaks.

We can now start coming up with plants we’d like to put in our garden. For this example, I’ve created Carrot, Potato, and Eggplant classes. Each of these classes has a unique implementation of the isRipe() function.

class Carrot : public Plant
{
public:
  Carrot()
  {
    color = "Orange";
    height = 0;
  }

  virtual bool isRipe() const
  {
    return height >= 10;
  }
};

class Potato : public Plant
{
  Potato()
  {
    color = "Brown";
    height = 0;
  }

  virtual bool isRipe() const
  {
    return height >= 7;
  }
};

class Eggplant : public Plant
{
  Eggplant()
  {
    color = "Purple";
    height = 0;
  }

  virtual bool isRipe() const
  {
    return height >= 13;
  }
};

Nothing too fancy here, but you can see that each class has a different (albeit simple) way of checking if the plant is ripe.

Moving forward, we can implement our Garden class. The Garden class is essentially a collection of plants. We’re going to store our plants in a vector. Well, really we’re storing pointers to our plants in a vector. Since there is no way of knowing how much memory each plant will use, we cannot store plants directly. We must store pointers to the plants, which could be of type potato, eggplant, or carrot.

class Garden
{
public:
  Garden();
  addPlant(Plant* p)
  {
    plants.push_back(p)
  }

  harvest()
  {
    for(int i=0; i<fplants.size(); i++)
    {
      if(plants[i]->isRipe())
      {
        plants.delete(plants.begin() + i) //Remove ripe plants from garden
      }
    }
  }

private:
  vector<*Plant> plants;
};

And there you have it. We have a very simple, and fairly useless e-garden. I’ll leave it up to you to code the army of slugs and snails to destroy it. Bring on the Gastropods!