Interface adaption, and private inheritance

A problem with code re-use

It’s a common situation in software development: you’ve acquired a class – either from a third-party source, or inherited from another project – that’s got some really useful features, but its interface doesn’t quite meet your immediate needs. Two typical scenarios are:

  • The interface is too big; you just want your clients to have a small subset of the facilities on offer.
  • The interface signatures don’t match what your client code needs (and you don’t want to – or can’t – change the client code.

 

clip_image002

Figure 1 – A mis-match between the interface the client requires and the interface provided by the utility class

The solution is to use the Adapter pattern – encapsulate the useful class within an object of your own devising and present a new interface for your client. There are two approaches to creating adapters – wrapping an object (known as the Object Adapter pattern) and the (less-well-known) Class Adapter pattern, which uses private inheritance (for more details on these patterns see Design Patterns. Elements of Reusable Object-Oriented Software, p139).

The Object Adapter pattern

In the Object Adapter pattern the Adapter class implements the service interface as required by the client but contains a nested object that implements the actual behaviour (see Figure 2)

clip_image004

Figure 2 – The Object Adapter pattern

/////////////////////////////////////////////////////////////////////
//
class IService
{
public:
  virtual void service1() = 0;
  virtual void service2() = 0;
  virtual void service3() = 0;
  virtual void service4() = 0;
};

/////////////////////////////////////////////////////////////////////
//
class UtilityProvider
{
public:
  void func1();
  void func2();
  void func3();
  void func4();

protected:
  void helperFunction();
};

 

The ObjectAdapter class realises the IService interface, and encapsulates a UtilityProvider object. There are three ways the UtilityProvider object can be bound to the ObjectAdapter:

  • The UtilityProvider object can be created by the client then passed in to the constructor of the ObjectAdapter. This is how the pattern is implemented in Design Patterns; and how it is done in this example.
  • The UtilityProvider can be created as a composite, nested object.
  • The UtilityProvider object can be allocated from the free store in the ObjectAdapter’s constructor and de-allocated in the ObjectAdapter’s destructor.

All three options are viable; but be careful with the second two if the ObjectAdapter instance is going to be copied (you will need to ensure the UtilityProvider object is properly copied)

/////////////////////////////////////////////////////////////////////
//
class ObjectAdapter : public IService
{
public:
  ObjectAdapter(UtilityProvider& obj) : utilityObject(obj) {}

private:
  virtual void service1()   // Simple pass-through call... 
  {
    utilityObject.func1();
  }

  virtual void service2()   // Combining behaviours...
  {
    utilityObject.func1();
    utilityObject.func2();
  } 

  virtual void service3()
  {
    // ... 
  }

  virtual void service4()
  {
    utilityObject.helperFunction();  // ERROR - protected member 
  }

  UtilityProvider& utilityObject;
};

/////////////////////////////////////////////////////////////////////
//
int main()
{
  UtilityProvider provider;
  IService& client = *(new ObjectAdapter(provider));

  client.service1();
  client.utilityObject.func1();  // ERROR – private object.

  // ...

  delete &client;
}

 

Note our client depends only the interface; not on any particular implementation. We can substitute our ObjectAdapter class since it inherits from the IService class.

Our new methods can be used to change the names (or signatures) of the UtilityProvider class’s methods. We can even combine Useful methods behind a more abstract interface.

Note, however, we cannot get access to any protected members of UtilityProvider.

Our client code can access our methods, but cannot get access to any of the methods of the (privately) nested UtilityProvider object.

Using private inheritance – the Class Adapter

The Class Adapter pattern uses private inheritance to encapsulate the UtilityProvider’s behaviour and present a new interface.

clip_image006

Figure 3 – The ClassAdapter inherits from both the Interface and the Implementation

Normally when we do inheritance in C++ we use public inheritance. Public inheritance does not change the access modifiers from the base class to the derived class. So public members in the base remain public in the derived; protected members remain protected; and private members remain private.

With private inheritance, any public or protected members in the base class become private in the derived class; and therefore become unavailable to clients of the derived class.

We make use of the change of access modifiers in the Class Adapter pattern. The ClassAdapter publically inherits from the IService interface (so the client can call its methods) but privately from the UtilityProvider (thus hiding all those methods)

/////////////////////////////////////////////////////////////////////
//
class ClassAdapter : public  IService,       // Interface
                     private UtilityProvider // Implementation
{
private:
  virtual void service1()
  {
    UtilityProvider::func1();
  }

  virtual void service2()
  {
    UtilityProvider::func1();
    UtilityProvider::func2();
  }

  virtual void service3()
  {
    // ... 
  }
  virtual void service4()
  {
    UtilityProvider::helperFunction();  // OK – Can access protected
  }
};

/////////////////////////////////////////////////////////////////////
//
int main()
{
  IService& client = *(new ClassAdapter);

  client.service1();

  // ...

  delete &client;
}

 

As before, we can add new methods to the Adapter class public interface. These methods then call on the base class operations. Again, we can combine methods to present a more abstract interface.

In addition, now we can access the protected members of the Useful class.

Simplifying an interface – the Adapting Façade

Often your client isn’t dependent on an interface, but you still might want to modify the interface of your utility class. Typically you’ll want to change a few methods and/or provide a subset of the original class’s interface.

Strictly, this isn’t the Adapter pattern. It’s actually a variation of the Façade pattern (Design Patterns. Elements of Reusable Object-Oriented Software, p187). The Façade pattern is designed to simplify access multiple subsystems, or non-OO APIs with a single, unified interface. In this case we only have one subsystem, our utility class. Let’s call it an Adapting Façade (for want of a better term).

/////////////////////////////////////////////////////////////////////
//
class AdaptingFacade : private UtilityProvider
{
public:
  void abstractMethod()
  {
    UtilityProvider::func1();
    UtilityProvider::func2();
  }

  // 'Expose' private methods from
  // Base class.
  //
  using UtilityProvider::func3;
};

/////////////////////////////////////////////////////////////////////
//
int main()
{
  AdaptingFacade adaptingFacade;

  adaptingFacade.abstractMethod();
  adaptingFacade.func1();            // ERROR cannot access private member
  adaptingFacade.func3();            // OK - exposed via 'using'
}

 

As with the Class Adapter pattern we use private inheritance to hide the utility class’s interface and present our own. Again, we can access protected members of the utility class. We can also make use of the using keyword to ‘expose’ private members of the Useful class into the Adapter Facade’s public interface. The method func3(), which was private (because of the private inheritance), has now been made public. This neat facility allows us to present a subset of the original class’s interface without the overhead of a pass-through call.

In summary

Both the Object Adapter pattern and Class Adapter patterns are valid ways of modifying an existing class’s interface to work better in a new environment. The Class Adapter pattern adds the benefit that you can access any protected members of the original class.

The Adapting Façade allows us to modify a class’s interface and also produce a reduced subset of the originals.

In the next article we’ll have a look at memory usage with the adapter patterns.

Glennan Carnie
Dislike (0)
Website | + posts

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry.

He specialises in C++, UML, software modelling, Systems Engineering and process development.

About Glennan Carnie

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry. He specialises in C++, UML, software modelling, Systems Engineering and process development.
This entry was posted in C/C++ Programming and tagged , , , , . Bookmark the permalink.

4 Responses to Interface adaption, and private inheritance

  1. Pingback: Improving the quality of large legacy codebase by incrementally enforcing encapsulation – Matej++

  2. Ces sont des infos vraiment intéressantes. Vous avez bien fait de rédiger cet article.
    Surtout, restez à la page et faites-nous profiter ! Merci
    beaucoup.

    Like (0)
    Dislike (0)
  3. Oh my goodness! Amazing article dude! Thank you so much, However I am going through troubles with your RSS.
    I don't know why I am unable to subscribe to it. Is there anybody else getting identical RSS issues? Anyone that knows the solution will you kindly respond? Thanks!!

    Like (0)
    Dislike (0)
  4. Pingback: Sticky Bits » Blog Archive » Template inheritance

Leave a Reply