Go backward to Template Instantiation.
Go up to C++ Extensions.

Type Abstraction using Signatures

   In GNU C++, you can use the keyword `signature' to define a
completely abstract class interface as a datatype.  You can connect this
abstraction with actual classes using signature pointers.  If you want
to use signatures, run the GNU compiler with the `-fhandle-signatures'
command-line option.  (With this option, the compiler reserves a second
keyword `sigof' as well, for a future extension.)

   Roughly, signatures are type abstractions or interfaces of classes.
Some other languages have similar facilities.  C++ signatures are
related to ML's signatures, Haskell's type classes, definition modules
in Modula-2, interface modules in Modula-3, abstract types in Emerald,
type modules in Trellis/Owl, categories in Scratchpad II, and types in
POOL-I.  For a more detailed discussion of signatures, see `Signatures:
A Language Extension for Improving Type Abstraction and Subtype
Polymorphism in C++' by Gerald Baumgartner and Vincent F. Russo (Tech
report CSD-TR-95-051, Dept. of Computer Sciences, Purdue University,
August 1995, a slightly improved version appeared in
*Software--Practice & Experience*, 25(8), pp. 863-889, August 1995).
You can get the tech report by anonymous FTP from `ftp.cs.purdue.edu'
in `pub/gb/Signature-design.ps.gz'.

   Syntactically, a signature declaration is a collection of member
function declarations and nested type declarations.  For example, this
signature declaration defines a new abstract type `S' with member
functions `int foo ()' and `int bar (int)':

     signature S
       int foo ();
       int bar (int);

   Since signature types do not include implementation definitions, you
cannot write an instance of a signature directly.  Instead, you can
define a pointer to any class that contains the required interfaces as a
"signature pointer".  Such a class "implements" the signature type.

   To use a class as an implementation of `S', you must ensure that the
class has public member functions `int foo ()' and `int bar (int)'.
The class can have other member functions as well, public or not; as
long as it offers what's declared in the signature, it is suitable as
an implementation of that signature type.

   For example, suppose that `C' is a class that meets the requirements
of signature `S' (`C' "conforms to" `S').  Then

     C obj;
     S * p = &obj;

defines a signature pointer `p' and initializes it to point to an
object of type `C'.  The member function call `int i = p->foo ();'
executes `obj.foo ()'.

   Abstract virtual classes provide somewhat similar facilities in
standard C++.  There are two main advantages to using signatures

  1. Subtyping becomes independent from inheritance.  A class or
     signature type `T' is a subtype of a signature type `S'
     independent of any inheritance hierarchy as long as all the member
     functions declared in `S' are also found in `T'.  So you can
     define a subtype hierarchy that is completely independent from any
     inheritance (implementation) hierarchy, instead of being forced to
     use types that mirror the class inheritance hierarchy.

  2. Signatures allow you to work with existing class hierarchies as
     implementations of a signature type.  If those class hierarchies
     are only available in compiled form, you're out of luck with
     abstract virtual classes, since an abstract virtual class cannot
     be retrofitted on top of existing class hierarchies.  So you would
     be required to write interface classes as subtypes of the abstract
     virtual class.

   There is one more detail about signatures.  A signature declaration
can contain member function *definitions* as well as member function
declarations.  A signature member function with a full definition is
called a *default implementation*; classes need not contain that
particular interface in order to conform.  For example, a class `C' can
conform to the signature

     signature T
       int f (int);
       int f0 () { return f (0); };

whether or not `C' implements the member function `int f0 ()'.  If you
define `C::f0', that definition takes precedence; otherwise, the
default implementation `S::f0' applies.