Pure virtual functions - Embedded.com

Pure virtual functions

Pure virtual functions provide a way to avoid defining base class member functions that have no meaningful implementation.

For much of this year, I've been explaining how virtual functions behave in C++ and how you can obtain similar behavior in C. Last summer, I showed how to emulate a polymorphic C++ class (a class with at least one virtual function) as a C structure that has an additional member commonly called a vptr (VEE-pointer).1 The vptr points to a table of function pointers called a vtbl (VEE-table). The past two months, I showed how to initialize the vptr in base and derived class objects.2, 3

This month, I'll explain the concept of pure virtual functions in C++. Although C doesn't provide native support for the concept, it's still applicable in C.

As in my prior articles, my sample classes represent an assortment of two-dimensional geometric shapes such as circle , rectangle , and triangle , all derived from a common base class called shape. The type hierarchy looks like:

The C++ definition for the shape base class looks in part like:

class shape {

and the definition for the circle class (derived from shape ) looks like:

class circle: public shape {public:    circle(double r, color o, color f); // constructor    virtual double area() const;    virtual double perimeter() const;    ~~~private:    double radius;};

The definition for the circle 's area function is as you should expect:

double circle::area() const {    return pi * radius * radius;}

The rectangle class derived from shape has members height and width instead of radius. The rectangle 's area function is also as you should expect:

double rectangle::area() const {    return height * width;}

What does shape 's area function look like? For that matter, what's a shape that's neither a circle , nor a rectangle , nor any other type derived from base class shape ?

Remember, the shape class represents a common interface for all shapes. For example, you can define a C++ function:

double volume(shape const *s, height h) {    return s->area() * h;}

which computes the volume of a solid with a base whose shape is s and whose height is h . You can then write:

v = volume(&c, 4.2);

to compute the volume of a cylinder whose base is circle c and whose height is 4.2.

Alternatively, you can define volume 's parameter s as a reference instead of a pointer, as in:

double volume(shape const &s, height h) {    return s.area() * h;}

Then you don't need to take the address of volume's first argument explicitly, as in:

v = volume(c, 4.2);

You get the same result whether you use a pointer or a reference.

With the hierarchy of shapes, it's meaningful to use a "pointer to shape " or a "reference to shape " to refer to a circle , rectangle , or triangle , or possibly some other shape that you might derive from the base class shape . It's also meaningful to have a shape object that's the base class part of some derived class object. However, it's not meaningful to have a shape object that's just a shape .

A meaningful shape has a radius, or a height and a width, or some other attributes that define its physical extent. A shape that's just a shape has no such attributes. Nonetheless, declaring an area function in the shape class is a meaningful thing to do. That function declaration becomes part of the interface for every shape derived from the base class shape . That is, it's a way of forcing derived classes such as circle and rectangle to have an area function.

Although declaring an area function for shape is meaningful, defining it is not because the base class lacks the attributes it needs to compute its area. Pure virtual functions provide a way to avoid defining such functions that have no meaningful implementation.

In C++, you declare a virtual function as a pure virtual function simply by placing = 0 at the end of the function heading in the function declaration. For example, in:

class shape {public:    shape(color o, color f);        // constructor    virtual double area() const = 0 ;    virtual double perimeter() const = 0 ;    ~~~private:    color outline, fill;};

the area and perimeter functions are now pure virtual functions. You need not define them for class shape .

If shape 's area and perimeter functions are undefined, what happens when you try to call them? I'll explain that in my next column. I'll also look at what you have to do to approximate the same behavior in C.

Dan Saks is president of Saks & Associates, a C/C++ training and consulting company. For more information about Dan Saks, visit his website at www.dansaks.com. Dan also welcomes your feedback: e-mail him at .

Endnotes:

  1. Saks, Dan, "Virtual functions in C," Embedded.com, August 8, 2012. www.embedded.com/4391967.
  2. Saks, Dan, "Initializing polymorphic objects," Embedded.com, October 17, 2012. www.embedded.com/4398820.
  3. Saks, Dan, "Initializing derived polymorphic objects," Embedded.com, November 15, 2012. www.embedded.com/4401463.

4 thoughts on “Pure virtual functions

  1. My comment has nothing to do with mechanics of pure virtual functions. I just want to get my two cent opinion in so other developers are aware. IMHO, the use of pure virtual functions to define a method which has no meaningufl implementation in a subclass

    Log in to Reply
  2. Pure virtual functions are the only way to achieve clean abstract interfaces in C++.

    While the shape class is a bit contrived, consider something more concrete to us embedded developers. Look at device drivers which implement open() close(), read(), write

    Log in to Reply
  3. An example would be “skew angle”. A rectangle can become a parallelogram, but skewing a circle makes no sense. (Skewing an oval might make sense, but not a circle.)

    The point is to make a top-level API that will last for many applications, and for that

    Log in to Reply
  4. Precisely, the open, close, read, write are meaningful methods for the derived classes of serial port and LCD. But if someone were to use the interface for an input only discrete interface, they would be misusing the interface.

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.