As is common in any programming language, the greatest boon usually also turns out to be the greatest bane. In C++, this comes in many forms. One of these is the lack of a globally-inherited object class, as there is in C#. This is a great advantage in that the overhead associated with a globally-inherited class is not present. It is a bane in that it results in a large degree of duplicated type-dependent code.
Take, for example, an STL list or map. If there were a global Object class, there would be a single implementation of sorting or red-black trees, which would be contained inside of a lib file. You wouldn't have large, complex algorithms in a .h header file, and you wouldn't have the same large algorithm replicated 10 times over for each type you've associated with the map or list.
Enter the objectify design pattern. It keeps the boon of C++ of not having (nor needing) a common, global Object class that all other objects, including simple types, inherit from. However, it still allows for type-independent algorithms to be stored away in a cpp file and compiled into a lib file. No massive inlining in sub-optimal compilers, no compilation of the same method 10 times.
There is, of course, a cost. As would be the case with a global Object class, type-independent functionality requires virtual functions. There is of course an overhead associated with this, usually in the form of an icache miss.
Conversely, because you are using a single common compiled function for all types which use a map or a list, this could also result in less icache misses. This is especially true if you are using maps of different types within a short period of time. The greatest boon, of course, is that your executable's memory footprint will be much smaller. In circumstances where this is a requirement, such as development on low-memory platforms (embedded systems, older game consoles), the boon far outweighs the bane.
Using the code
1 2 3 4 5 6 7 8
|
class _list_base
{
protected:
Objectify::Comparable& m_comparable;
_list_base (Objectify::Comparable& comparable) : m_comparable(comparable) {}
public:
void sort ();
};
|
In the sort function, we would use m_comparable to safely compare instances of the objects in the list:
|
m_comparable.Compare(node_data(p), node_data(q))
|
The templatized class, list<> would look as follows:
1 2 3 4 5 6 7 8 9
|
template<typename ListElementType>
class list : protected _list_base
{
public:
list()
: _list_base(Objectify::Typed::Comparable<ListElementType>::s_Comparable)
{
}
}
|
For a zip file containing the sources and a sample list class with a fully-functional merge sort, go to: