A little word from Stroustrup:
Many classes resemble class Employee in that they are useful both as themselves and also as bases
for derived classes. For such classes, the techniques described in the previous section suffice.
However, not all classes follow that pattern. Some classes, such as class Shape, represent abstract
concepts for which objects cannot exist. A Shape makes sense only as the base of some class
derived from it. This can be seen from the fact that it is not possible to provide sensible definitions
for its virtual functions:
Code:
class Shape {
public:
virtual void rotate(int) { error("Shape: :rotate") ; } / / inelegant
virtual void draw() { error("Shape: :draw") ; }
/ / ...
};
Trying to make a shape of this unspecified kind is silly but legal:
Code:
Shape s; / / silly: ‘‘shapeless shape’’
It is silly because every operation on s will result in an error.
A better alternative is to declare the virtual functions of class Shape to be pure virtual functions.
A virtual function is ‘‘made pure’’ by the initializer = 0:
Code:
class Shape{ / / abstract class
public:
virtual void rotate(int) = 0; / / pure virtual function
virtual void draw() = 0; / / pure virtual function
virtual bool is_ closed() = 0; / / pure virtual function
/ / ...
};
A class with one or more pure virtual functions is an abstract class, and no objects of that abstract
class can be created:
Code:
Shape s; / / error: variable of abstract class Shape
An abstract class can be used only as an interface and as a base for other classes. For example:
Code:
class Point{ /* ... */ };
class Circle : public Shape {
public:
void rotate(int) { } / / override Shape::rotate
void draw() ; / / override Shape::draw
bool is_ closed() { return true; } / / override Shape::is_closed
Circle(Point p, int r) ;
private:
Point center;
int radius;
}
A pure virtual function that is not defined in a derived class remains a pure virtual function, so the
derived class is also an abstract class. This allows us to build implementations in stages:
Code:
class Polygon : public Shape{ / / abstract class
public:
bool is_ closed() { return true; } / / override Shape::is_closed
/ / ... draw and rotate not overridden ...
};
Polygon b; / / error: declaration of object of abstract class Polygon
class Irregular_ polygon : public Polygon {
list<Point> lp;
public:
void draw() ; / / override Shape::draw
void rotate(int) ; / / override Shape::rotate
/ / ...
};
Irregular_ polygon poly(some_ points) ; / / fine (assume suitable constructor)
An important use of abstract classes is to provide an interface without exposing any implementation
details. For example, an operating system might hide the details of its device drivers behind an
abstract class:
Code:
class Character_ device {
public:
virtual int open(int opt) = 0;
virtual int close(int opt) = 0;
virtual int read(char* p, int n) = 0;
virtual int write(const char* p, int n) = 0;
virtual int ioctl(int ...) = 0;
virtual ~Character_ device() { } / / virtual destructor
};
We can then specify drivers as classes derived from Character_ device, and manipulate a variety of
drivers through that interface.
With the introduction of abstract classes, we have the basic facilities for writing a complete program
in a modular fashion using classes as building blocks.
Hope this helps!