Design Patterns [01]

Using template-template-parameters with policy classes is not simply a matter of convenience; sometimes, it is essential that the host class have access to the template so that the host can instantiate it with a different type. An alternative to using template-template-parameters is to use template member functions in conjunction with simple classes. That is, the policy implementation is a simple class (as opposed to a template class) but has one or more templated members.
Modern C++ Design Generic Programming and Design Patterns Applied – Page 6: This analysis suggests that a combination of templates and multiple inheritance could engender a very flexible device, appropriate for creating libraries of design elements.
Modern C++ Design Generic Programming and Design Patterns Applied – Page 9: Note that policies are quite different from mere virtual functions. Virtual functions promise a similar effect: The implementer of a class defines higher-level functions in terms of primitive virtual functions and lets the user override the behavior of those primitives. As shown above, however, policies come with enriched type knowledge and static binding, which are essential ingredients for building designs. Aren't designs full of rules that dictate before runtime how types interact with each other and what you can and what you cannot do? Policies allow you to generate designs by combining simple choices in a type-safe manner. In addition, because the binding between a host class and its policies is done at compile time, the code is tight and efficient, comparable to its handcrafted equivalent. Of course, policies' features also make them unsuitable for dynamic binding and binary interfaces, so in essence policies and classic interfaces do not compete.
Clients who need enriched policies can benefit from that rich functionality, without affecting the basic functionality of the host class. Don't forget that users—and not the library—decide which policy class to use. Unlike regular multiple interfaces, policies give the user the ability to add functionality to a host class, in a type-safe manner.
There is an additional important detail about creating policy classes. Most often, the host class uses public inheritance to derive from its policies. For this reason, the user can automatically convert a host class to a policy and later delete that pointer. Unless the policy class defines a virtual destructor, applying delete to a pointer to the policy class has undefined behavior.
Defining a virtual destructor for a policy, however, works against its static nature and hurts performance. Many policies don't have any data members, but rather are purely behavioral by nature. The first virtual function added incurs some size overhead for the objects of that class, so the virtual destructor should be avoided. A solution is to have the host class use protected or private inheritance when deriving from the policy class. However, this would disable enriched policies as well. The lightweight, effective solution that policies should use is to define a nonvirtual protected destructor:
template <class T>
struct OpNewCreator
{
static T* Create()
{
return new T;
}
protected:
~OpNewCreator() {}
};
Because the destructor is protected, only derived classes can destroy policy objects, so it's impossible for outsiders to apply delete to a pointer to a policy class. The destructor, however, is not virtual, so there is no size or speed overhead.
C++ contributes to the power of policies by providing an interesting feature. If a member function of a class template is never used, it is not even instantiated—the compiler does not look at it at all, except perhaps for syntax checking.
Notes:
***.
(2016-02-08)

No comments:

Post a Comment