You are currently browsing the archives for the Virtual Functions tag.

Adapter pattern memory models

June 8th, 2012

Following on from the article on Adapter patterns (Read more here) I’ve decided to explore the memory models of each of these patterns.

We’ll start with the simple case of a UtilityProvider class being a simple class with no virtual methods. Then we’ll look at what happens when the UtilityProvider has virtual functions added.

To flesh out the memory models I’ve added (arbitrary) data to both the UtilityProvider class and its adapters.

These memory models are based on the IAR Embedded Workbench C++ compiler. It’s a fairly typical compiler for embedded systems development. For simplicity I’m ignoring padding issues; compilers will usually pad to the next word boundary, so assume what you see is word-aligned objects.

The Object Adapter

A quick reminder of the Object Adapter pattern. The ObjectAdapter class realises the IService interface and forwards on all calls to the encapsulated UtilityProvider object. The Utility provider object can be created by the client and passed in the adapter, allocated on the free store by the adapter, or stored as a nested (composite) object.

clip_image002

Figure 1 – The Object Adapter pattern

Object Adapter memory model

If the UtilityProvider is created outside the adapter (or on the free store) the memory model is as shown in Figure 2. Note the ObjectAdapter class has a vtable pointer since it implements the IService interface. The de-facto model is to place the vtable pointer as the first element in the class (in other words at ‘this’)

clip_image004

Figure 2 – ObjectAdapter with a reference to the UtilityProvider object

If the UtilityProvider object is a composite object the memory model changes (Figure 3). Note, the ObjectAdapter vtable pointer is still the first element in the object.

clip_image006

Figure 3 – ObjectAdapter with nested UtilityProvider

The Class Adapter pattern

A Class Adapter realises the client-required interface but privately inherits from the UtilityProivder class (hiding its methods) – See Figure 4

clip_image008

Figure 4 – The Class Adapter pattern

Class Adapter memory model

The memory model for inheritance in C++ constructs a base class object as part of the derived class, so we should expect a memory model similar to that of the composite-object Object Adapter. In fact, it is identical( Figure 5)

clip_image010

Figure 5 – Class Adapter

Adding virtual functions to the UtilityProvider.

Suppose our UtilityProvider class has virtual functions (for example Figure 6). How does this affect the memory model?

/////////////////////////////////////////////////////////////////////
//

class UtilityProvider
{
public:
  UtilityProvider();
  void func1();
  void func2();
  void func3();
  void func4();
  virtual void func5(); // Requires a vtable.

protected:
  void helperFunction();

private:
  // Private data.
};

Figure 6 – UtilityProvider with virtual functions

The Object Adapter memory model

When the UtilityProvider class has virtual functions it gets its own vtable and vtable pointer (Figure 7). It’s worth noting the order in which the memory is allocated depends on the order of declaration in the class definition. In this example I’ve put the UtilityProvider object as the first declaration; before any other data.

Note also that the ObjectAdapter’s vtable pointer is still the first element in the object.

clip_image012

Figure 7 – Object Adapter with virtual UtilityProvider

Class Adapter memory model

In a single-inheritance model the derived class shares its vtable pointer with the base class (that’s the basis of polymorphism. In the case of the Class Adapter model this isn’t the case. Both the ClassAdapter and UtilityProvider retain their own vtable pointers. (This allows the ClassAdapter to have a virtual function with the same signature as the UtilityProvider, and still call the UtilityProvider’s virtual function. If they shared the same vtable pointer you could end up with an infinite recursive call)

There is also a difference on memory layout depending on whether the IService interface is the Primary Base Class and the UtilityProvider is a Secondary Base Class( Figure 9); or vice versa (Figure 10)

You should always favour having the Interface as the Primary Base Class. For more information on why see this white paper.

/////////////////////////////////////////////////////////////////////
//
class ClassAdapter : public IService, // Primary Base Class
                     private UtilityProvider // Secondary Base Class
{
  // ....
};

/////////////////////////////////////////////////////////////////////
//
class ClassAdapter : private UtilityProvider, // Primary Base Class
                     public IService // Secondary Base Class
{
  // ....
};

Figure 8 – ClassAdapter definitions with different PBC and SBC

clip_image014

Figure 9 – ClassAdapter with IService as Primary Base Class

clip_image016

Figure 10 – ClassAdapter with UtilityProvider as Primary Base Class

Summary

The memory models of the Adapter patter are all very similar. Remember when programming these patterns the associated overheads:

  • Extra code space for the vtable(s)
  • An extra vtable pointer for each object with virtual functions
  • The overhead of virtual function calls (note the double overhead if you are calling a virtual function on the original class!)

Inheritance, ABCs and Polymorphism

March 14th, 2011

Virtual functions

Virtual functions in C++ exist to maintain the consistent behaviour of polymorphism when accessing derived objects via base class pointers. (If that statement has made your head spin, I’d suggest reading this article before carrying on)

class Base
{
public:
  virtual void v_op();
};

class Derived : public Base
{
public:
  virtual void v_op();
}

I can access either a Base object or a Derived object via a Base pointer; and I should get the appropriate behaviour for the actual type of the object I’m pointed at:

Base* pB;
pB = new Base;	  // Point at Base object…
pB->v_op(); 	  // calls Base::v_op()
pB = new Derived  // Derived object is also a Base object
pB->v_op()	  // this time calls Derived::v_op()

This mechanism is known as dynamic polymorphism.
Dynamic polymorphism is a very powerful mechanism for building flexible, maintainable solutions. If we base the client code not on a particular object but on a more abstract (in the design sense) super class (something known as the Dependency Inversion Principle) we can swap implementations in and out without having to re-factor the client code (using a principle called Substitutability).

Abstract Base Classes

Let’s take a common design problem. During design we identify a set of classes with some similar behaviour but some unique behaviour. For example, our design may require concurrent behaviour so we define a set of ‘active’ classes, each one doing a different task:

class ActiveComms
{
public:
  void start();    // Create a thread; and call doStuff()
  void doStuff();  // Perform this class’ behaviour
};

class ActiveDisplay
{
public:
  void start();    // Create a thread; and call doStuff()
  void doStuff();  // Perform this class’ behaviour
};

class ActiveControl
{
public:
  void start();    // Create a thread; and call doStuff()
  void doStuff();  // Perform this class’ behaviour
};

These objects share common behaviour – they all have to create and manage a thread of control in the underlying OS – but they all have (at least one) unique behaviour – the actual work they are doing (for example, managing the display)
Rather than replicating the common code it is put into a base class and the ‘working’ classes inherit from it. We make the unique behaviour virtual so that derived classes can provide their own (overridden) implementation.

class Active
{
public:
  void start();            // Create a thread; ; and call doStuff()
  virtual void doStuff();  // What should this function do?
};

class ActiveComms : public Active
{
  virtual void doStuff();  // ActiveComm’s unique behaviour
};

In the client code we can use dynamic polymorphism to decouple us from any particular implementation:

Active* pActiveObject;
pActiveObject = new ActiveComms;   // Derived class
pActiveObject->start(); 	   // Assume start() calls
                                   // polymorphic doStuff()

What’s to stop us creating a base class object, though?

Active* pActiveObject;
pActiveObject = new Active;        // Base class object.  Correct, but…
pActiveObject->start(); 	   // what happens here?

What happens when the base class object runs? What does its doStuff() function do? At best it may do some generic (common) behaviour; at worst nothing at all.
In reality we don’t want clients to create objects of the common base type. They’re a convenience to improve intrinsic quality, not really part of the functional behaviour. In order to inhibit creation of base class objects we make the virtual function pure.

class Active
{
public:
  void start();                // As before
  virtual void doStuff() = 0;  // Pure virtual function.
};

Active is now referred to as an Abstract class. You cannot create an instance of an abstract class. This is because a pure virtual function does not require an implementation. (We’ll talk about what happens if you try and call this base class function in a while). Derived classes must implement the doStuff() function; they then become what are called Concrete classes.

// Active* pActiveObject = new Active     // Fails – Active is abstract
Active* pActiveObject = new ActiveComms;  // Concrete class
pActiveObject->start();

What happens if a derived class calls the base class’ (pure) virtual fuction? C++ scope operator (::) allows you to call a function outside your current scope; and in fact anywhere in the class hierarchy.

// Class declarations as before.
void ActiveComms::doStuff() 	// virtual function
{
  // Do ActiveComms unique behaviour…
  Active::doStuff();            // Call base class’ (pure) virtual function.
                                // This is legal, but what happens?!
}

What happens when you write code like this depends on your compiler. On most modern compilers – for example GCC, IAR or even Microsoft! – you will get a Linker error when you compile this code. This is because there is no implementation for the pure virtual function (as expected).
Be careful, though: on some older compilers declaring a function as a pure virtual may cause the compiler to insert a null (zero) into the vtable for the class. The code compiles and links with no errors or warnings. When the code executes and the pure virtual function is called (via the vtable) it will execute a null pointer. On many processors this is the reset vector; meaning your call to the base class pure virtual function will reset your system (with no warning!)

Pure Virtual Functions with Implementations

So, can you provide an implementation for a pure virtual function? And why would I want to?
In our example, let’s assume there is some common behaviour that all our concrete classes have to perform as part of their doStuff() function. It makes sense to collect the common behaviour together in the base class – but, we still don’t want clients to create instances of the base class, Active.
Remember, adding (at least one) pure virtual functions to a class makes it an abstract class, meaning you cannot create an instance of it. A pure virtual class is not required to have an implementation – but that doesn’t mean you can’t provide an implementation.
The solution to our problem is to keep the Active class exactly as before but add an implementation to its doStuff() pure virtual function that contains all the common behaviour. This common behaviour can be called from the overridden derived classes’ doStuff() function:

class Active
{
public:
  void start();                // As before
  virtual void doStuff() = 0;  // Pure virtual function.
};

void Active::doStuff()		// Pure virtual function implementation!
{
  // Common behaviour goes in here.
}

class ActiveComms : public Active
{
  virtual void doStuff();  // ActiveComm’s unique behaviour
};

void ActiveComms::doStuff() 	// virtual function
{
  // Call base class’ (pure) virtual function.
  // Contains all the common behaviour.
  //
  Active::doStuff();       

  // Do ActiveComm's unique behaviour…
}

The design and use of pure virtual functions is two-fold:

  • To create abstract classes which acts as a common interface (or contract) to client code. Derived concrete classes can be substituted for the abstract base class (using dynamic polymorphism). The abstract base class designer must specify the (only) set of services the client can expect.
  • To force derived classes to provide their own implementation of the function. The abstract base class designer must specify which parts of the implementation can be shared and which must be unique.

Use of abstract base classes and substitution, using pure virtual functions and dynamic polymorphism allows you to build flexible and adaptable solutions, particularly in areas of your system that will be subject to change over the life of the system.

%d bloggers like this: