Sunday, May 25, 2008

C++ inheritance: a simple example

Suppose we want to write a scientific plotting application using Qt that can make simple 2D plots as well as 3D plots. One option would be to make two classes, Plot2D and Plot3D. For example:
class Plot2D
{
   public:
      Plot2D();
      ~Plot2D();
      void setAxisLimitsX(int, int);
      void setAxisLimitsY(int, int);
      void setNumDataPoints(int);
      void setData(float *x, float *y);
   private:
      QImage *plot;
};

Plot3D
{
   public:
      Plot3D();
      ~Plot3D();
      void setAxisLimitsX(int, int);
      void setAxisLimitsY(int, int);
      void setAxisLimitsZ(int, int);
      void setNumDataPoints(int);
      void setData(float *x, float *y, float *z);
   private:
      QImage *plot;
};
Clearly, both classes are quite similar. Both have methods for setting the x-axis limits, the y-axis limits, the number of data points, and a QImage containing the actual plot. The only differences are that Plot3D has an additional method for setting the z-axis limits, and the setData method has an additional array for the 3rd component of the data.

An alternative to the above is to use inheritance. We make a class called Plot:
class Plot
{
   public:
      Plot();
      ~Plot();
      void setAxisLimitsX(int, int);
      void setAxisLimitsY(int, int);
      void setNumDataPoints(int);
      void setData(float *x, float *y);
   private:
      QImage *plot;
};
This is very general and has methods and data that apply to both 2D and 3D plots. We can now define the Plot2D and Plot3D classes:
class Plot2D : public Plot
{
   public:
      Plot2D();
      ~Plot2D();
};

class Plot3D : public Plot
{
   public:
      Plot3D();
      ~Plot3D();
      void setAxisLimitsZ(int, int);
      void setData(float *x, float *y, float *z);
};
These two classes (known as derived classes) inherit from the Plot class, and contain all public and protected variables of the base class Plot (but not private variables). For example, both Plot2D and Plot3D here have access to setAxisLimitsX and setAxisLimitsY. However, note that the constructors and destructors of base classes are not inherited.

The use of inheritance enables code to be reused. After defining the base class, we don't need to define the same features in multiple derived classes. This sames time!

No comments: