We
are remarkably adaptable, even with things where perhaps we
shouldn’t
adapt. The style of the
CStash
library has been a staple for C programmers, but if you look at it for a while,
you might notice that it’s rather . . . awkward. When you use it, you
have to pass the address of the structure to every single function in the
library. When reading the code, the mechanism of the library gets mixed with
the meaning of the function calls, which is confusing when you’re trying
to understand what’s going on.
One
of the biggest obstacles, however, to using libraries in C is the problem of
name
clashes.
C has a single name space for functions; that is, when the linker looks for a
function name, it looks in a single master list. In addition, when the compiler
is working on a translation unit, it can only work with a single function with
a given name.
Now
suppose you decide to buy two libraries from two different vendors, and each
library has a structure that must be initialized and cleaned up. Both vendors
decided that
initialize( )
and
cleanup( )
are good names. If you include both their header files in a single translation
unit, what does the C compiler do? Fortunately, C gives you an error, telling
you there’s a type mismatch in the two different argument lists of the
declared functions. But even if you don’t include them in the same
translation unit, the linker will still have problems. A good linker will
detect that there’s a name clash, but some linkers take the first
function name they find, by searching through the list of object files in the
order you give them in the link list. (Indeed, this can be thought of as a
feature because it allows you to replace a library function with your own
version.)
In
either event, you can’t use two C libraries that contain a function with
the identical name. To solve this problem, C library vendors will often prepend
a sequence of unique characters to the beginning of all their function names. So
initialize( )
and
cleanup( )
might become
CStash_initialize( )
and
CStash_cleanup( ).
This is a logical thing to do because it “mangles” the name of the
struct
the function works on with the name of the function.
Now
it’s time to take the very first step into C++. Variable names inside a
struct
do not clash with global variable names. So why not take advantage of this for
function names, when those functions operate on a particular
struct?
That is, why not make functions members of
structs?