C++ Programming/Classes/Abstract Classes/Pure Abstract Classes

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Pure Abstract Classes[edit | edit source]

An abstract class is one in which there is a declaration but no definition for a member function. The way this concept is expressed in C++ is to have the member function declaration assigned to zero.

Example
class PureAbstractClass 
{
public:
  virtual void AbstractMemberFunction() = 0;
};

A pure Abstract class has only abstract member functions and no data or concrete member functions. In general, a pure abstract class is used to define an interface and is intended to be inherited by concrete classes. It's a way of forcing a contract between the class designer and the users of that class. The users of this class must declare a matching member function for the class to compile.

Example of usage for a pure Abstract Class
 class DrawableObject 
 {
  public:
    virtual void Draw(GraphicalDrawingBoard&) const = 0; //draw to GraphicalDrawingBoard
 };

 class Triangle : public DrawableObject
 {
 public:
   void Draw(GraphicalDrawingBoard&) const; //draw a triangle
 };

 class Rectangle : public DrawableObject
 {
 public:
   void Draw(GraphicalDrawingBoard&) const; //draw a rectangle
 };

 class Circle : public DrawableObject
 {
 public:
   void Draw(GraphicalDrawingBoard&) const; //draw a circle
 };

 typedef std::list<DrawableObject*> DrawableList;

 DrawableList drawableList;
 GraphicalDrawingBoard drawingBoard;

 drawableList.pushback(new Triangle());
 drawableList.pushback(new Rectangle());
 drawableList.pushback(new Circle());

 for(DrawableList::const_iterator iter = drawableList.begin(), 
    endIter = drawableList.end();
    iter != endIter;
    ++iter)
 { 
   DrawableObject *object = *iter;
   object->Draw(drawingBoard);
 }

Note that this is a bit of a contrived example and that the drawable objects are not fully defined (no constructors or data) but it should give you the general idea of the power of defining an interface. Once the objects are constructed, the code that calls the interface does not know any of the implementation details of the called objects, only that of the interface. The object GraphicalDrawingBoard is a placeholder meant to represent the thing onto which the object will be drawn, i.e. the video memory, drawing buffer, printer.

Note that there is a great temptation to add concrete member functions and data to pure abstract base classes. This must be resisted, in general it is a sign that the interface is not well factored. Data and concrete member functions tend to imply a particular implementation and as such can inherit from the interface but should not be that interface. Instead if there is some commonality between concrete classes, creation of abstract class which inherits its interface from the pure abstract class and defines the common data and member functions of the concrete classes works well. Some care should be taken to decide whether inheritance or aggregation should be used. Too many layers of inheritance can make the maintenance and usage of a class difficult. Generally, the maximum accepted layers of inheritance is about 3, above that and refactoring of the classes is generally called for. A general test is the "is a" vs "has a", as in a Square is a Rectangle, but a Square has a set of sides.