OOC:en:2.2 Methods, Messages, Classes and Objects

来自 ChinaUnix Wiki

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;
};
struct Set {
    const void * class; /* must be first */
        ...
};

Each of our objects starts with a pointer to its own type description, and through this type description we can locate type-specific information for the object: .size is the length that new() allocates for the object; .ctor points to the constructor called by new() which receives the allocated area and the rest of the argument list passed to new() originally; .dtor points to the destructor called by delete() which receives the object to be destroyed; .clone points to a copy function which receives the object to be copied; and .differ points to a function which compares its object to something else.

Looking down this list, we notice that every function works for the object through which it will be selected. Only the constructor may have to cope with a partially initialized memory area. We call these functions methods for the objects. Calling a method is termed a message and we have marked the receiving object of the message with the parameter name self. Since we are using plain C functions, self need not be the first parameter.

Many objects will share the same type descriptor, i.e., they need the same amount of memory and the same methods can be applied to them. We call all objects with the same type descriptor a class; a single object is called an instance of the class. So far a class, an abstract data type, and a set of possible values together with operations, i.e., a data type, are pretty much the same.

An object is an instance of a class, i.e., it has a state represented by the memory allocated by new() and the state is manipulated with the methods of its class. Conventionally speaking, an object is a value of a particular data type.

个主工具