Design Con 2015

Initializing derived polymorphic objects

November 15, 2012

Dan_Saks-November 15, 2012

This assignment requires a cast because circle_vtbl isn't exactly the same type as shape_vtbl. The two structures have the same memory layout, but the corresponding pointers in the different structures point to functions with slightly different types.

Thus, the derived class constructor contains two assignments to the vptr. The second assignment completely overwrites the value assigned by the first. Ideally, the compiler will "optimize away" the first assignment. However, the compiler can do this optimization only if it can see both assignments in the context of the derived class constructor, which it can do only if the base class constructor is an inline function.

If you define the shape_construct function as inline, you should move the function definition to the shape.h header file. When you do that, you must also give the_shape_vtbl external linkage by removing the keyword static from its definition, as in:

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

~~~

shape_vtbl the_shape_vtbl = { // used to be static
    shape_area,
    shape_perimeter
};

~~~

If your C compiler supports the inline keyword (from C99), then the shape.h header would look in part like:

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

~~~

typedef struct shape shape;

~~~

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

extern shape_vtbl the_shape_vtbl;

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

inline
void shape_construct(shape *s, color o, color f) {
    s->vptr = &the_shape_vtbl;
    s->outline = o;
    s->fill = f;
}

If your compiler doesn't support the keyword inline, then you can implement the constructor as a macro:

 
#define shape_construct(s, o, f) ( \
    (s)->vptr = &the_shape_vtbl, \
    (s)->outline = (o), \
    (s)->fill = (f) \
)

Either way, a compiler with a decent optimizer should eliminate the redundant assignment to the vptr.

Once again, you don't have to worry about any of this in C++. With C++, the compiler automatically generates code to initialize the vptr properly.

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 dan@dansaks.com..

< Previous
Page 2 of 2
Next >

Loading comments...

Parts Search Datasheets.com

KNOWLEDGE CENTER