ACCU Buttons

Exploring Patterns Part 2

Before I focus on the pattern for this issue I want to tell you
about something that I learnt whilst doing further research for the
Singleton pattern.

As most of you know, declaring a copy constructor for a class
inhibits the compiler from generating its own. After considerable
pressure from several people (I think I was among the most
vociferous) WG21 & J16 specified that all the following were
classified as copy-constructors (for the sake of example, I am
assuming that I am dealing with a class MyType):

In addition all constructors with a first parameter matching one
of those four and defaults for all the other parameters will also
be copy constructors. The clarification concerned whether the
volatile qualified parameters resulted in inhibiting the compiler
from generating a copy constructor or a default constructor. Note
my wording, I fondly believed that any constructor would only
inhibit one or other but not both of the possible compiler
generated ones. This believe seems to be shared by many good, even
expert, writers. On numerous occasions I have had cause to point
out the flaw in code such as:

class MyType
{
MyType();
public:
// whatever
};

where the clear intent is that it should not be possible to
create public instances of MyType. The
flaw is due to a quirk of the grammar for declarations that results
in the following code being syntactically correct (though usually
hiding undefined behaviour because storage is copied before it has
been initialised):

Mytype mt = mt;

It is the quirky grammar for initialisation in this form that
leads me to strongly recommend that you always use the function
form for user defined types. If you wrote:

MyType mt(mt);

You would get a compile time error unless an mt of appropriate
type had been declared in an outer scope. In other words, always
call a constructor explicitly rather than use an implicit
constructor and call to the copy constructor. Actually, as more
programmers recognise that object types (as opposed to value types)
should not have publicly accessible copy constructors the problem
will occur less often.

Back to the main point. Unless you have declared one of the copy
constructor forms, the compiler is at liberty to attempt to
generate one of the form MyType(Mytype const
&).

However when I have raised the issue of the missing declaration
of a private copy constructor, all I have ever had is 'Ahh… I missed that' and the
writer has added a copy constructor. None of them has ever removed
their declaration of a default constructor. I think, that like me,
many of them have always thought in terms of two almost disjoint
sets of constructors, copy constructors and non-copy constructors
(with an overlap caused by defaulting parameters so as to leave a
more general constructor useable as a copy constructor). Even
though I have explicitly made that statement (about two disjoint
sets) in the presence of some of the World's greatest C++ experts,
none have ever corrected me (perhaps some of them just heard what
they expected, and some were too polite - though I doubt it, that
kind of politeness is unhelpful).

In fact, declaring a copy constructor inhibits the compiler from
generating a default constructor as well as any other copy
constructor. This means that if you want to prevent public creation
of a type all you need to do is to declare a private copy
constructor. For example:

class MyType
{
MyType(Mytype &);
public:
// whatever
};

correctly does what was intended by the earlier flawed case.

So we see that the correct idiom for a class that must not be
publicly constructable is to declare a private copy
constructor.

Now we also need to know what to do if we want to prevent
copying but are happy to allow default construction (needed for
example if you are intending to provide dynamic arrays of the type
- but not the STL containers that require access to a copy
constructor). The fix is easy:

class MyType
{
MyType(Mytype &);
public:
MyType(){};
// whatever
};

That default constructor with an empty body tells the compiler
to do exactly what it would have done had it been able to generate
a default constructor for itself.

The Visitor
Pattern

When you read the following please do
not take my word for it, wait until the experts have had a look and
either confirm, extend or correct my interpretation. Think of this
as an essay being read by a student at a seminar, only after the
discussion is complete will those involved know confidently what is
true and what is not.

In general we are concerned with providing stable, well-defined
behaviour for our abstractions. At the same time we want to reserve
the right to change implementation details. This is the main motive
for the concept of private/protected/public
interfaces. However there are cases where we have a clear idea
about how we wish to provide our data but wish to reserve the right
to alter behaviour.

One way of tackling this problem is by using a base class to
provide the data (together with protected
read and write member functions) and using derived classes (or
classes with pointers to the desired data structure) to provide the
behaviour. This works well where we have a single fundamental data
type but it does not work when we need a hierarchy. One example
given (in Design Patterns) of such a hierarchy is that of the
different node types required for a parse tree used by a compiler
for a computer language. For example in C the node for an
assignment must provide a left pointer to an expression node that
evaluates as a modifiable lvalue and a right pointer to an
expression node that evaluates to an rvalue. Arithmetic operator
nodes need left and right pointers to nodes for expressions
evaluating to rvalues.

While the data requirements are very stable (fortunately
computing languages infrequently add features requiring new node
types) the desired behaviour can change. Indeed the desired
behaviour will depend on exactly what you are trying to do(compile,
optimise etc.). It is usually unwise to have an interface cluttered
with a large number of member functions, particularly if these are
only tenuously related to each other. Even if we could provide an
exhaustive list of all the behaviour we want in such a class
hierarchy it is probably a poor idea to provide it in the
classes.

The idea behind the Visitor pattern is to allow programmers to
encapsulate coherent behaviour across a number of classes (not
necessarily even in the same hierarchy) into a single class.
Typically, we have something like:

class A_type;
class B_type;
class C_type;
// etc.

These declarations can be replaced with definitions and the
various classes are usually part of a hierarchy but this is not
necessary for the pattern to work.

This is an abstract base class from which concrete classes
providing single behaviours can be derived. Actually all the
functions could share the same function name as overloading would
resolve which one to use. Whether you use function overloading or
not is a matter of style (shorter names requiring thoughtful
reading versus longer names providing specific information). If the
visitor is not intended to mutate (change the state of) the host
objects then the parameters in the above should be of type
const *.

Each of the classes to be visited must include a member function
of the form:

MyVisitor & host(MyVisitor &);

Again, const qualification should be
used as appropriate: const member function
if the Visitor is non-mutating and const
qualified parameter if the Visitor is not mutated by visiting.

The body of host() depends upon the
class in which it is placed so that it calls the appropriate member
function of the Visitor. For example:

If you have chosen the function overloading mechanism then all
host types will have apparently identical bodies (though the type
of 'this' will select the correct overload version from the
visitor's members functions):

MyVisitor & A_type::host(MyVisitor & v)
{
return v.Visitor(this);
}

The return type of the host functions and the members of the
visitor could be void but I have a strong preference for returning
an object for possible reuse. It doesn't cost much but provides one
extra resource for those that wish to use it.

Let me offer a trivial example where you want to be able to
dispatch the data to some form of output. You would write something
such as:

Now we come to a problem. The bodies of the member functions of
StoreData require access to the specific
data of the host classes. This means that each of these classes
must provide public access functions for
its data (this does not break encapsulation but it does restrict
the owners of the host classes (but remember that a pre-condition
for the use of the Visitor pattern is stable data structures).

Remember that the advantage of the Visitor pattern is that you
can retrofit behaviour to a bunch of (usually related) classes. Of
course, you can install any specific behaviour into the classes
themselves, but one major advantage of the Visitor pattern is that
it supports extensible behaviour.

It also works well where you have collections of objects, or
even composites of heterogeneous objects. Design Patterns gives the example of something like
a piece of equipment (such as a computer) that is built from
components that are themselves built from components etc. If you
want to cost such equipment you could (if you thought far enough
ahead) provide a visitor object that was passed around collecting
cost information from each sub-component (to do that it would have
to visit each sub-sub component recursively). This may sound
complicated until you realise that all that is required is that the
host() function of a component
dispatches the visitor to each of the sub-components before calling
the specific member function of the visitor object on itself.

I think that the Visitor pattern is a powerful program technique
that deserves to be widely known. If you are serious about software
development you should work through at least one implementation of
Visitor to ensure that you understand it and will remember to
provide the groundwork where it has potential use. For example, the
Harpist's Hotel project might benefit from a Visitor facility in
all classes that provide charges (a bill is made up from a variety
of costs that are certainly not all from objects in the same
hierarchy; think about meals and rooms.) Of course this problem has
many other solutions (such as ensuring that each object includes a
reference/pointer to a bill object) and the lack of the need for
extensible behaviour probably makes other methods more
appropriate.

Before I wrap this up I want to speculate a bit on the
possibility of avoiding the need for public read/write access
functions for data in host classes.

Keeping Data
Out of Reach

The first thought when tackling this problem (restricting access
to data) is to consider using friendship. Unfortunately there is no
mechanism for granting friendship to a hierarchy of classes and
part of the fundamentals of the design of the Visitor pattern seems
to require a hierarchy. We need a base class so that the parameter
of the host() functions can provide
polymorphic behaviour (select the type of behaviour that the
visitor is going to add). But that does not mean that we need a
hierarchy of derived types (to which friendship can only be granted
on a one by one basis, which would rather defeat the object of the
exercise).

Unfortunately, though templates can declare friends and ordinary
classes can declare instances of templates to be friends there is
no syntax available to declare a template class as a friend. So
this idea may be interesting but it does not solve the problem of
finding a way whereby the various host classes can provide
privileged access rights to a Visitor hierarchy.

My next idea was to try and increase the security by using
namespaces coupled with fuzzing the types used (remember that the
data types/structures for the host classes must be stable if we are
using the Visitor pattern.) This is my first attempt:

I hoped that by hiding the typedef in a
namespace that its implicit use outside the namespace would create
an error. I agree that this was a pretty vain hope because a
typedef does not create real type. Of
course this code compiled.

Unfortunately, the so called Koenig lookup allows the compiler
to find the Int type in the context of
obj.set_value(3) and obj.get_value(). I had one last shot in my locker
(remember that my purpose is to make it possible to force
programmers to think about using the access functions they have in
host classes). Consider:

Now the two function calls in question fail and require an
explicit cast (for seti) and a call to
convert_to_int (for geti) to make the
compiler happy.

So, if there is data in a host class that you are reluctant to
make easily accessible to the world at large, but that you do need
to make available to Visitor, you can add this extra layer.
Visitors will have to use this as well, but we are assuming that we
are catering for data that needs thoughtful use.

Conclusion

I have learnt a lot while putting this article together, and I
know I have ranged further afield than strictly required for the
topic. However, I think some of the ideas and failed attempts may
prove instructive. What I do know is that the process of active
exploration rather than passive reading is what provides the value
to me. I think the same will apply to you.

Postscript

It has just occurred to me that there is one other mechanism
available. Have each host class that has data that you do not want
to make generally accessible declare the visitor ABC (MyVisitor for
example) a friend. Now you can place those access functions that
you want to restrict in the protected interface of the ABC. That
way all the concrete visitors will have the access they need but
no-one else will. Here is some code by way of example.

The above code is untested so it is up to you to debug it, in
doing so you will need to understand it.

Post-Postscript

Before writing this article I had thought there was a way of
declaring a template class a friend. When I failed to get my code
to compile I checked with a couple of UK C++ experts who opined
that it was not possible, hence the assertion. I have now had a
chance to check the FDIS and find that my original belief is
justified though the syntax is counter-intuitive.

The inclusion of the line:

template<Operations> friend class Guest;

in each host class should provide the desired access. However, I
cannot find a compiler to compile it. Anyway, I believe that my
postscripted solution is technically better as well as being
compilable with the current compiler releases.