A wrapper is a driver stub that emulates some API library and converts them to calls to another driver's API.
The common issues with such drivers are:
  1. API calls are seldom mappable 1-to-1. That forces unwanted complexity and performance hit compared to the target driver or the emulated one, and introduces reliability problems.
  2. When wrappers are custom-made to support certain applications, they neglect to implement API calls which are not used by the targeted application; The wrapper is then unsuitable for any other purpose.
  3. By perpetuating support for deprecated APIs; they stall re-engineering of existing applications using the older APIs and stifle adoption of newer APIs.

Example of wrappers:

An object-oriented programming idiom in which a class is constructed to act like another type. The concept serves as a basis (but probably NOT as a base class) for a number of programming idioms and design patterns: handles, proxies, pimpls, observers, smart pointers, constrained classes, and the like.

A class has wrapper behavior for a type T if it has enough members to allow a class user to:

  • assign a class instance a value of type T.
  • extract a T value so assigned back out of the instance.
class TWrapper
{
 T get();
 put (T);
};

In most object-oriented languages, class users are forced to call get() or put() every time we want to access or change the inner value. C++ lets us sugarcoat these members, making the syntax of their use a bit less awkward:

template <class T>
class Wrapper
{
 T v;

 public:
 explicit Wrapper (T const &iv) { v = iv; }
 operator T const &() const { return v; }
 Wrapper &operator=(T const &nv) { v=nv; return *this; }
};

According to some, it's even easier in Perl, with the help of a little runtime code generation. I'll have to leave it to others to write that up.

You're sitting there and thinking: "Wait a minute! aren't we just adding overhead to a T object? Why not just use a T object?" You would never use a class like the template above, since it doesn't do anything a T won't do.

Wrapper classes are usually constructed to control access to a "real" T object. "Access control" covers several categories of behaviors, all semantically different, so we're going to defer specific descriptions of such behaviors (such as the patterns and idioms that are lnked in the first paragraph) to the writeups discussing them. For now, we'll assume there's a good reason:

template <class T>
class Wrapper
{
 T v;

 protected:
 control() const;
 control();

 public:
 explicit Wrapper (T const &iv) { v = iv; }
 operator T const &() const { control(); return v; }
 Wrapper &operator=(T const &nv) { control(); v=nv; return *this;}
};

The class designer has to be careful not to thwart this purpose. It would have been easy to screw up the above template by adding another coversion operator to return a non-const reference to a T:

 operator T &() { return v; }

But then there'd be no way to call control()! For our little example template, we could certainly do this:

 operator T &() { control(); return v; }

But consider a different implementation of a wrapper class (something I call a "representation class"):

template <class T, class I=T>
class Wrapper
{
 I v;

 protected:
 control() const;
 control();

 public:
 explicit Wrapper (T const &iv) { v = iv; }
 operator T const &() const { control(); return v; }
 Wrapper &operator=(T const &nv) { control(); v=nv; return *this;}
 operator T &() { control(); return v; } //wtf?
};

A specialization of Wrapper where I is a different type from T won't compile, because of the member we added. So, we'll probably have to live without it. If we do that, however, we will have ot scale back our goal of using a Wrapper everywhere a T can be used. Consider:

template <class T>
class Foo
{
 bar (T &);
};

Unless we can get at a T& somehow, there's no way to call Foo<T>::bar(T&). If you want to extract a T value from an istream into a Wrapper<int> we can't call operator>>(istream &, int &). Instead, we'll have to write a stream extractor explicitly for wrappers,

template <class T>
istream &operator>>(istream &is; Wrapper<T> w)
{
 T t;
 is>> t;
 w=t;
 return is;
}

Ungainly, but that may be the best way to do it. There's no easy answer: You'll just have to balance the access control needs of the particular wrapper class you're designing with the other functionality you want out of it.

Wrap"per (?), n.

1.

One who, or that which, wraps.

2.

That in which anything is wrapped, or inclosed; envelope; covering.

3.

Specifically, a loose outer garment; an article of dress intended to be wrapped round the person; as, a morning wrapper; a gentleman's wrapper.

 

© Webster 1913.

Log in or registerto write something here or to contact authors.