原创 The concept of pure virtual functions

2012-12-20 18:47 3608 24 24 分类: 消费电子

In my previous blogs, I've been explaining how virtual functions behave in C++ and how you can obtain similar behaviour in C. A few months ago, 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 initialise 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:

1212embsaks01.gif


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


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


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 behaviour in C.


Endnotes:
1. Saks, Dan, "Implementing Virtual functions in C," Eetindia.co.in, August 14, 2012.
2. Saks, Dan, "How to properly initialise polymorphic objects," Eetindia.co.in, October 25, 2012.
3. Saks, Dan, "Learn to Initialise derived polymorphic objects," Eetindia.co.in, November 22, 2012.
 

文章评论0条评论)

登录后参与讨论
我要评论
0
24
关闭 站长推荐上一条 /2 下一条