Storage layout for polymorphic objects
Adding at least one virtual function to a class alters the storage layout for all objects of that class type.
Earlier this year, I explained how virtual functions support dynamic function call binding in C++. (See “Virtual Functions in C++,” Embedded.com, April 2012, www.eetimes.com/4370404 ). This month, I'll begin to explain how C++ compilers typically implement virtual functions by explaining how using virtual functions affects the storage layout for objects.
As before, 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
. All of the shapes also have common attributes, such as position, and outline and fill colors. Each derived class adds some linear or angular distance(s) to characterize the physical extent of the shape. For example, a circle
has a radius, a rectangle
has a height and a width, and a triangle
has two sides and an angle.
The definition for the base class shape
looks in part like:
class shape {public: shape(); // constructor virtual double area() const; virtual double perimeter() const; ~~~private: coordinates position; color outline, fill;};
(As at least one reader observed earlier, the shape
class should probably be an abstract base class with pure virtual functions. I haven't covered that subject yet, and it's not relevant to this discussion. Ditto for virtual destructors.)
If the area
and perimeter
member functions weren't virtual, then the functions wouldn't occupy any storage within shape
objects. The storage for a shape
object would contain only the storage for the data members, as shown in Figure 1 .

Figure 1: The storage layout of a shape object if class shape had no virtual functions.
However, shape
's area
and perimeter
member functions are virtual. A class type, such as shape
, with a least one virtual function is a polymorphic type . An object of polymorphic type is a polymorphic object . C++ compilers typically add a pointer to the storage layout of each polymorphic object. That pointer is commonly called a vptr (“VEE-pointer”) and it points to a table of function pointers called a vtbl (“VEE-table”).
C++ compilers don't create vptrs and vtbls unless needed. Thus, non-polymorphic types don't have vptrs and vtbls.
Each polymorphic type has its own vtbl. That vtbl contains one pointer for each virtual function in the class. For example, the shape
class has two virtual functions, area
and perimeter
, so shape
's vtbl contains one pointer to shape
's area
function and another to shape
's perimeter
function, as shown in Figure 2.

shape
objects and shape
's vtbl.
Figure 2 shows the vptr situated at the beginning of each shape
. Some compilers place the vptr after the last data member, instead. Each compiler can do as it pleases, as long as every object of a given polymorphic type has the same storage layout.
Each derived class inherits all the data members of its base class. Inherited members must have the same offsets within the derived class as they do in the base class. (This is true for classes with only one base class. It may not be true for classes with multiple base classes–a complication that I'm going to ignore for now.)
A class derived from a polymorphic base class will be polymorphic as well, and it inherits the base class's vptr. The vptr must have the same offset in the base class subobject (the base class portion) of a derived class object as it does in a base class object.
For example, you can derive the circle
class from shape
as follows:
class circle: public shape {public: circle(double r); // constructor virtual double area() const; virtual double perimeter() const; ~~~private: double radius;};
The circle
class is polymorphic and it defines its own versions of area
and perimeter
. The compiler generates a distinct vtbl for class circle
. Except that each circle
object has an additional data member, radius
, the storage layout for circle
objects, shown in Figure 3 , is identical to the layout for shape
objects.

Figure 3: The storage layout for circle
objects and circle
's vtbl.
As another example, here's class rectangle
derived from shape:
class rectangle: public shape {public: rectangle(double h, double w); virtual double area() const; virtual double perimeter() const; ~~~private: double height, width;};
Except that each rectangle
object has additional data members height
and width
, the storage layout for rectangle
objects, shown in Figure 4 , is identical to the layout for shape
objects.

Figure 4: The storage layout for rectangle
objects and rectangle
's vtbl.
I'll have more to say in future columns about how virtual functions work and how you can emulate them in C.
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 .
Please elaborate the meaning of line “inherited members must have the same offsets within the derived class as they do in the base class”.
“Hallo Dan Saks, Forst many for this worth courses, that I have recently discovered. I have a little question here, I do not understand why you have the two virtual methods “area” and “perimeter” also declared as so in the derived class. The derived cl