Go to the first, previous, next, last section, table of contents.


7.10 Abstract Classes

In C++, a class is an abstract class if it has any pure virtual member functions. In C++, a member function is declared as a pure virtual function by writing = 0 instead of the usual function body (see Section 10.3 of [Ellis-Stroustrup90]). Because pure virtual functions have no implementation, no objects of such a class can be constructed. Hence such a class can only be used as a base class for other classes. A class is concrete if it has no pure virtual member functions. When a class is derived from a class with pure virtual member functions, it will only be concrete if each pure virtual function member is overridden instead of inherited (see Section 10.2 [Ellis-Stroustrup90]).

In Larch/C++, a member function specified in a class can only be implemented by a pure virtual function if its interface is specified as a pure virtual function. In addition, a class can be specified to be an abstract class by prefixing its specification with the keyword abstract. This tells the writer of a derived class that the pure virtual member functions must be implemented to obtain a concrete class.

In Larch/C++ one may also declare a class to be abstract without specifying any pure virtual member functions. This tells the reader that the no objects of the class should be created. In an abstract class, there are no implicitly generated specifications (see section 7.2.3 Implicitly Generated Member Specifications).

An example of an abstract class specification is the following specification of IntList. It uses the trait List from the LSL Handbook (page 173 [Guttag-Horning93]). Instead of defining a trait, simply to include NoContainedObjects, that trait is used directly (see section 7.5 Contained Objects for details on why this is done). All the member functions are in this specification are pure virtual, except for length. This is because length can be programmed with the others, and so the specification states that it must be implemented normally. Note that even for pure virtual members a specification is given.

// @(#)$Id: IntList.lh,v 1.13 1997/06/03 20:29:38 leavens Exp $

//@ uses List(int for E, IntList for C), NoContainedObjects(IntList);

/*@ abstract @*/ class IntList {
public:
  virtual bool is_null() const throw() = 0;
  //@ behavior {
  //@   ensures result = (self\any = empty);
  //@ }

  virtual int head() const throw() = 0;
  //@ behavior {
  //@   requires ~(self\any = empty);
  //@   ensures result = head(self\any);
  //@ }

  virtual IntList* tail() const throw() = 0;
  //@ behavior {
  //@   requires ~(self\any = empty);
  //@   ensures isValid(result) /\ (*result)' = tail(self\any);
  //@ }

  virtual int length() const throw();
  //@ behavior {
  //@   requires len(self\any) <= INT_MAX;
  //@   ensures result = len(self\any);
  //@ }
};

Other useful features for specifying abstract classes are invariants (see section 7.3 Class Invariants) and history constraints (see section 7.4 History Constraints).


Go to the first, previous, next, last section, table of contents.