Design Con 2015

Implementing a derived class vtbl in C

February 13, 2013

Dan_Saks-February 13, 2013

There's more than one way to implement a derived class vtbl in C. Dan looks at two alternatives.

For more than a year now, I've been discussing polymorphic types and virtual functions. I explained how to use virtual functions in C++ as well as how to implement and use virtual functions in C.[1],[2] More specifically, 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). The vptr points to a table of function pointers called a vtbl (VEE-table).

Last November, I showed how to initialize derived polymorphic objects.[3] My colleague, Miro Samek, raised a very interesting question about one of my implementation choices, and offered an alternative approach. While his alternative has merit, I still think my approach is preferable and I'll try to explain why. In any event, it's worth considering both techniques because the discussion raises interesting questions about interface design and maintainability.

I'll begin this month by explaining Miro's question in detail.

Once again, 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 C++ definition for the shape base class looks in part like:

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


In C, the comparable declarations look like:

// shape.h - a C base class for shapes

#ifndef SHAPE_H_INCLUDED
#define SHAPE_H_INCLUDED

typedef struct shape shape;

typedef struct shape_vtbl shape_vtbl;
struct shape_vtbl {
    double (*area)(shape const *s);
    double (*perimeter)(shape const *s);
};

struct shape {
    shape_vtbl *vptr;
    color outline, fill;
};

void shape_construct(shape *s, color o, color f);
double shape_area(shape const *s);
double shape_perimeter(shape const *s);

#endif


In C++, the definition for a 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;
};


I rendered the derived class in C using the following declarations:
// circle.h – a C class for circle derived from shape

#ifndef CIRCLE_H_INCLUDED
#define CIRCLE_H_INCLUDED

#include "shape.h"

typedef struct circle circle;
struct circle {
    shape base;     // the base class subobject
    double radius;
};

void circle_construct(circle *c, double r, color o, color f);
double circle_area(circle const *c);
double circle_perimeter(circle const *c);

#endif


When I showed this header in previous articles, I omitted the declarations for circle_area and circle_perimeter (shown above in red). I didn't need them in the prior discussion, so I left them out for brevity. However, in general, they should be there.

Article continues on page 2...



[1] Saks, Dan, "Virtual Functions in C++," Embedded.com, April 4, 2012. www.embedded.com/4370404.

[2] Saks, Dan, "Virtual functions in C," Embedded.com, August 8, 2012. www.embedded.com/4391967.

[3] Saks, Dan, "Initializing derived polymorphic objects," Embedded.com, November 15, 2012. www.embedded.com/4401463.

[4] Ibid.

[5] Saks, Dan, "Storage layout for polymorphic objects," Embedded.com, July 21, 2012. www.embedded.com/4390835.

< Previous
Page 1 of 2
Next >

Loading comments...

Parts Search Datasheets.com

KNOWLEDGE CENTER