Reflections on virtual functions in C

June 12, 2013

Dan_Saks-June 12, 2013

For some time now, I’ve been explaining how to implement and use virtual functions in C.[1],[2]  The basic approach is to implement each class as a C structure and implement each associated method as a function whose first parameter is a pointer to the structure.  For each polymorphic class (a class with at least one virtual function), the corresponding C structure has a member called a vptr, which points to a table of function pointers called a vtbl.

Last month, I showed how to mimic class inheritance in C in two distinct ways, which I call “inheritance by composition” and “inheritance by copying and editing.”[3]  The two approaches differ in how they declare the vptrs and vtbls.  I’m planning to show other variations, but not just yet.  Rather, I want to pause and reflect on why I’m covering this topic.

A few years ago, I wrote a series of columns on representing memory-mapped devices as objects in C and in C++.[4],[5]  Over the following year or so, I elaborated on the techniques, introducing other C++ features as appropriate.[6] A few readers objected to my C++ implementations for failing to use virtual functions.  This issue came up repeatedly, so I decided to address virtual functions in depth.

My goal in writing this series was to explain what virtual functions are and how typical C++ compilers implement them.  Most embedded.com readers use C rather than C++.[7]  Thus, I thought the best way to show how C++ typically implements virtual functions is to show how to implement virtual functions in C to get functionality and performance very similar to what you get from C++.  I figured those of you already using C++ might learn more about how virtual functions work, and those of you using C might learn some techniques you can use in your code.  I was also hoping to help some C users realize that C++ really is better for object-oriented programming.

If you program in C, but you also want to do object-oriented programming, you probably should be using C++ instead of C. Yes, I know, some of you have constraints that prevent you from using C++.  Some of you program on platforms for which no C++ compiler exists, or the available compilers don’t mesh well with other tools you’re using. In that case, you can approximate object-oriented features in C using techniques like the ones I’ve been describing.  But don’t kid yourself.  Compared to C++, virtual functions in C are cumbersome and error-prone, and rarely offer any performance advantage.

Indeed, C has a few features that C++ lacks, such as the restrict qualifier, which facilitates certain optimizations.  But if you need these features, and your C++ compiler doesn’t support them as extensions, you can write selected portions of your code in C.  Needing these features is a poor reason to use C for everything, when C++ is so much better than C for object-oriented programming (as well as other things).

Next time, I’ll continue discussing the details of implementing virtual functions in C, not only because it’s useful to know, but also because it touches on various other interesting programming topics.

Dan Saks is president of Saks & Associates, a C/C++ training and consulting company. E-mail him at dan@dansaks.com.


[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, “Alternative idioms for inheritance in C,” Embedded.com, April 1, 2013.  www.embedded.com/4411013.

[4] Saks, Dan, “Alternative models for memory-mapped devices”, Embedded Systems Design, May 2010, p. 9.  www.embedded.com/4027659.

[5] Saks, Dan, “Memory-mapped devices as C++ classes”, Embedded.com, June 2010.  www.embedded.com/4200755.

[6] Saks, Dan.  “Using member new to map devices,” Embedded.com, November 2011.  www.embedded.com/4230743.

[7] Saks, Dan.  “Unexpected trends,” Embedded System Design, May 2, 2012.  www.embedded.com/4372180.

Loading comments...