12
___________________________________________________________________________
2 Dynamic Linkage — Generic Functions
It looks like we have another problem: somebody needs to copy the destructor
pointer dtor from the type description to destroy in the new object and the copy
may have to be placed into a different position in each class of objects.
Initialization is part of the job of
new() and different types require different work
— new() may even require different arguments for different types:
new(Set); /* make a set */
new(String, "text"); /* make a string */
For initialization we use another type-specific function which we will call a
construc-
tor. Since constructor and destructor are type-specific and do not change, we pass
both to new() as part of the type description.
Note that constructor and destructor are not responsible for acquiring and
releasing the memory for an object itself — this is the job of new() and delete().
The constructor is called by new() and is only responsible for initializing the memory
area allocated by new(). For a string, this does involve acquiring another piece of
memory to store the text, but the space for struct String itself is allocated by
new(). This space is later freed by delete(). First, however, delete() calls the des-
tructor which essentially reverses the initialization done by the constructor before
delete() recycles the memory area allocated by new().
2.2 Methods, Messages, Classes and Objects
delete() must be able to locate the destructor without knowing what type of object
it has been given. Therefore, revising the declarations shown in section 2.1, we
must insist that the pointer used to locate the destructor must be at the beginning
of all objects passed to delete(), no matter what type they have.
What should this pointer point to? If all we have is the address of an object,
this pointer gives us access to type-specific information for the object, such as its
destructor function. It seems likely that we will soon invent other type-specific
functions such as a function to display objects, or our comparison function differ(),
or a function clone() to create a complete copy of an object. Therefore we will use
a pointer to a table of function pointers.
Looking closely, we realize that this table must be part of the type description
passed to new(), and the obvious solution is to let an object point to the entire type
description:
struct Class {
size_t size;
void * (* ctor) (void * self, va_list * app);
void * (* dtor) (void * self);
void * (* clone) (const void * self);
int (* differ) (const void * self, const void * b);
};
struct String {
const void * class; /* must be first */
char * text;
};