Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Part Four.  Cognizant Conversions


Chapter 21. Veneers

Veneer: A thin leaf or layer of a more valuable or beautiful material for overlaying an inferior one.

Veneers are used to layer type, functionality, or both, over existing types in a fine-grained manner. A veneer is often used to add that "final touch" to an existing, substantial type. It may also be a way to bind specific behavior to a simple type. Think of veneers as being a jar of fine polish in your cognizant-conversion toolbox.

Definition: Veneers

A veneer is a template class with the following characteristics:

  1. It derives, usually publicly, from its primary parameterizing type.

  2. It accommodates, and adheres to, the polymorphic nature of its primary parameterizing type. This means that a veneer cannot define any virtual methods of its own, though it can override those defined by its primary parameterizing type.

  3. It may not define any nonstatic member variables.

The consequence of 2 and 3 is that a veneer may not change the memory footprint of its primary parameterizing type, and this is achieved by virtue of the Empty Derived Optimization (EDO; see section 12.4), a very widely supported optimization. In other words, instances of a veneer composite have the same size as the primary parameterizing type.


These constraints distinguish the veneer concept from similar concepts and are provided to ensure that it is legitimate for veneer types to do two things that are normally proscribed by accepted C++ good practice: passing arrays of inherited types by pointer and deriving from nonpolymorphic types.

We saw the problem of arrays of inherited types in Chapter 14, along with the array_proxy template class, which may be used by libraries to protect themselves against inappropriate use. The array_proxy enforces the rejection of unsuitable types being passed as arrays, while specifically allowing the expected/defining type of the array and any derived types that have the same memory footprint. Veneers represent the other side of the solution to this problem, in that they help enforce design decisions and provide a measure of protection when used with functions that are not protected by array_proxy or an equivalent mechanism.

Before I introduce the second, more commonly applied characteristic of veneers, I want to reiterate what was said in Chapter 14 about using arrays of inherited types: Don't do it! It's a hazardous thing to do, often indicates bad (or at least hasty) design, and will get you cutting remarks in code reviews unless you can justify why you've done so. Given that, however, you may have cause to occasionally define such functions, and I've no doubt that you'll come across them, so one aspect of the veneer concept is to give you some measure of protection when you must work in this fashion.

The second feature of veneers, whose use is significantly less contentious, is in the requirement to respect the polymorphic nature of the parameterizing type, which legitimizes the application of veneers to, and hence the inheritance from, nonpolymorphic types, a practice that is normally frowned upon.

Veneers have a broad conceptual scope. Where one constraint pertains to the classic virtual function based polymorphic capabilities of C++, the other finds utility in C++'s generic programming capabilities. Veneers can be put to a wide variety of uses, sometimes quite surprising ones, and this chapter illustrates both aspects of the concept by demonstrating some of these uses.


      Previous section   Next section