A further specification of an S3 class can be made if the
  class is guaranteed to have some attributes of known class (where as
  with slots, “known” means that the attribute is an object of
  a specified class, or a subclass of that class).
In this case, the call to setOldClass() can supply an S4 class
  definition representing the known structure.  Since S4 slots are
  implemented as attributes (largely for just this reason), the known
  attributes can be specified in the representation of the S4 class.
  The usual technique will be to create an S4 class with the desired
  structure, and then supply the class name or definition as the
  argument S4Class= to setOldClass().
See the definition of class "ts" in the examples below and
  the data.frame example in Section 10.2 of the reference.
  The call to setClass to create the S4 class can use the same
  class name, as here, so long as the call to setOldClass
  follows in the same package.  For clarity it should be the next
  expression in the same file.
In the example, we define "ts" as a vector structure with a
  numeric slot for "tsp".  The validity of this definition relies
  on an assertion that all the S3 code for this class is consistent with
  that definition; specifically, that all "ts" objects will
  behave as vector structures and will have a numeric "tsp"
  attribute. We believe this to be true of all the base code in R, but
  as always with S3 classes, no guarantee is possible.
The S4 class definition can  have virtual superclasses (as in
  the "ts" case) if the S3 class is asserted to behave
  consistently with these (in the example, time-series objects are
  asserted to be consistent with the '>structure class).
Failures of the S3 class to live up to its asserted
  behavior will usually go uncorrected, since S3 classes inherently
  have no definition, and the resulting invalid S4 objects can cause
  all sorts of grief.  Many S3 classes are not candidates for known
  slots, either because the presence or class of the attributes are
  not guaranteed  (e.g., dimnames in arrays, although these are
  not even S3 classes), or because the class uses named components of
  a list rather than attributes (e.g., "lm").  An attribute
  that is sometimes missing cannot be represented as a slot, not even
  by pretending that it is present with class "NULL", because
  attributes, unlike slots, can not have value NULL.
One irregularity that is usually tolerated, however, is to optionally
  add other attributes to those guaranteed to exist (for example,
  "terms" in "data.frame" objects returned by
  model.frame).  Validity checks by
  validObject ignore extra attributes; even if this check
  is tightened in the future, classes extending S3 classes would likely
  be exempted because extra attributes are so common.