Previous | Table of Contents | Next |
CLOS allows you to incrementally extend other, previously defined classes to create a new class. The new class inherits both structure (or slots) and behavior from the other classes, or superclasses. Looked at the other way round, the new class is known as a subclass of its superclasses. Smalltalk uses the same terminology, but in C++, a subclass is known as a derived class, which inherits from an existing base class.
Consider the following example:
(defclass circle () ((center :initform (make-instance point)) (radius :initform 1.0))) (defclass fillable-circle (circle) ((fill-pattern :initform blue-stipple :initarg :fill :accessor fill-pattern) (radius :initform 2.0)))
The class fillable-circle is a subclass of circle and inherits the slots center and radius from its superclass, circle, plus the newly defined fill-pattern slot for a total of three slots. The radius slot has an :initform that overrides the :initform specified in the circle superclass, so in essence it is the same slot as in the superclass, but with a different initialization. This is unlike C++, where there would be two slots named radius, independently accessible depending on the declared type of the object. In Smalltalk, it is illegal for subclasses to declare instance variables of the same name as a superclass. CLOS and Smalltalk are alike, but unlike C++, in that the slots (or instance variables) in an instance of a class are the union of the unique slot names in the class and its superclasses.
Longer chains of class definitions are common. For example, you might have a class chain such as region as a superclass of convex-region, which is a superclass of circle (note that this would require a redefinition of circle as defined in the previous example to inherit from convex-region). In this case, circle inherits directly from convex-region and indirectly from region. convex-region is called the direct superclass of circle and a superclass of fillable-circle. Similarly, fillable-circle is a direct subclass of circle, which in turn is a direct subclass of convex-region.
CLOS supports multiple inheritance: A subclass can inherit from more than one direct superclass. The typical use of multiple inheritance is to define mix-in classesthat is, classes that encapsulate independent behavior, which allows the programmer to better control the total possible number of combinations of possible classes. By clearly factoring the problem into independent components in advance, its much easier to understand how classes of interest in the application relate to each other and when new classes should be defined. Mix-in classes are not designed to have instances. Instances are always made from specialized classes that inherit from the principal class and one or more mix-in classes. To give an example, you can factor the preceding example into shapes and fill-patterns by using mix-in classes in the following way:
(defclass fill-pattern-mix-in () ((fill-pattern :initform blue-stipple :initarg :fill :accessor fill-pattern))) (defclass fillable-circle (fill-pattern-mix-in circle) ((radius :initform 2.0)))
Note that this example would lend itself to factoring out colors as an independent component as well; you would have a color-mix-in, and fillable-circle would inherit from fill-pattern-mix-in, color-mix-in, and the circle class.
Multiple inheritance is sometimes confusing when the components arent independent and some of the superclasses have the same named slots. CLOS resolves this using a default rule, which is described in section 5.4.4.
Previous | Table of Contents | Next |