Impure thoughtsOnce more unto the breach, Dan tries to dispel the notion that C++ is a purely object-oriented language in which all classes must use virtual functions.
Object-oriented programming employs a combination of techniques: data abstraction, inheritance, and polymorphism. C++ supports data abstraction by providing classes and objects. It supports inheritance via class derivation and polymorphism via virtual functions.
Since the beginning of the year, I've written several articles on polymorphic types and virtual functions in C and C++.1, 2, 3, 4 I wrote these articles in response to comments that readers posted regarding some of my earlier columns on representing and manipulating memory-mapped devices. I still have more to say about implementing virtual functions, but before I proceed with that, I'd like to address a higher-level class design issue.
As I explained in the first article of this series on virtual functions, some readers claimed that my C++ classes for memory-mapped devices are flawed—not because they don't work, but because they don't use inheritance and virtual functions. I think this claim is misguided.
A polymorphic type is a class with at least one virtual function. C++ compilers typically implement virtual functions by adding a pointer called a vptr to the storage layout for each polymorphic type. However, the storage layout for a class representing a memory-mapped device must match the layout of the device's memory-mapped registers. Using virtual functions in a device class adds a vptr that disrupts the match between the class layout and device register layout. Therefore, classes that represent memory-mapped devices can't use virtual functions.
Despite this restriction, you can still use a hierarchy of polymorphic types to represent a family of related memory-mapped devices. You just have to do it indirectly. That is, you use polymorphic objects in ordinary memory to provide abstract behaviors. Then you implement those behaviors by accessing non-polymorphic objects mapped directly to the hardware device registers. (I expect to show the details in a future column.)
The inability to use virtual functions in memory-mapped device classes is a problem only if you subscribe to the ill-founded notion that C++ should be used purely as an object-oriented language—a language in which all classes are polymorphic. It's a notion that many of us in the C++ community having been trying for years to dispel. In fact, Bjarne Stroustrup, the inventor of C++, has several items about this on his FAQ list.5
For example, under the item What is C++?, Stroustrup wrote:
C++ is a general-purpose programming language with a bias towards systems programming that: • is a better CNotice that he described C++ as a "general-purpose" language that "supports object-oriented programming," not as an object-oriented language. If you click on object-oriented programming in the list above, it takes you to another item with a link to a paper he wrote entitled "Why C++ isn't just an object-oriented programming language."6 You might want to read it. Elsewhere in his FAQ, under "Is C++ an Object-Oriented language?, Stroustrup wrote:
• supports data abstraction
• supports object-oriented programming
• supports generic programming
C++ is a multi-paradigm programming language that supports Object-Oriented and other useful styles of programming. If what you are looking for is something that forces you to do things in exactly one way, C++ isn't it.Stroustrup has a separate FAQ list on C++ style and technique.7 One item worth noting is entitled "Why are member functions not virtual by default?" under which he wrote:
Because many classes are not designed to be used as base classes. For example, see classThe C++ Standard itself also describes C++ as a "general purpose programming language based on the C programming language".8 Most of the classes and class templates in the Standard C++ Library are not polymorphic. The idea that C++ must be used as a purely object-oriented language runs counter to its design and prevents programmers from using it effectively.
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 firstname.lastname@example.org..
- Saks, Dan. "Discriminated unions," Embedded Systems Design, March 2012, p. 9. www.embedded.com/4237055.
- Saks, Dan. "Virtual Functions in C++," Embedded.com, April 4, 2012. www.embedded.com/4370404.
- Saks, Dan. "Storage layout for polymorphic objects," Embedded.com, July 21, 2012. www.embedded.com/4390835.
- Saks, Dan. "Virtual functions in C," Embedded Systems Design, August 8, 2012. www.embedded.com/4391967.
- Stroustrup, Bjarne, Bjarne Stroustrup's FAQ, www.stroustrup.com/bs_faq.html.
- Stroustrup, Bjarne. "Why C++ is not just an object-oriented programming language," OOPSLA ‘95 Addendum to the proceedings of the 10th annual conference on Object-oriented programming systems, languages, and applications, p. 1. 1995, ACM.
- Stroustrup, Bjarne. "Bjarne Stroustrup's C++ Style and Technique FAQ," www.stroustrup.com/bs_faq2.html. ISO/IEC Standard 14882:2011, Programming languages--C++.