[comp.lang.c++] Problem with specification & implementations

ijd@otter.hpl.hp.com (Ian J Dickinson) (07/17/90)

This is a small query that needs a big-ish introduction, so skip now if you
don't like big postings.


I have recently (within the last 3 weeks) started learning C++ (using HP's C++
product, but I don't think that's relevant to the problem), and I have come
across the following problem.

I am writing an abstract data-type for a finite map.  The range which is any
enumerated type (cast to integers) and the domain is any class which has a
GenericClass as a base class.  Now, I want to write one specification of the
interface for a finite map, but have several implementations - in particular a
full map (based on arrays) and a sparse map (based on binary trees).  I don't
want to be able to assign one from the other, or anything complicated like
that, but I do want both implementations to exist in the same application (with
different names, obviously).

I thought, when I designed this bit of the code (and at which time I had not
much C++ experience) that I could declare a class for the Map signature:

  class Map {
  public:
      virtual Generic lookupMap( int );
      // Return a pointer to the domain object in the map for range element
      // alpha.  Returns NULL if alpha is not in the range.
  
      virtual Map *mapAdd( int, Generic );
      // Adds generic object beta to the range for alpha.  The previous
      // domain object for alpha (if any) is released.  This version is 
      // referentially transparent, as the old map is left unchanged and a 
      // new map is returned.
  
      .... etc etc ...
  
  private:
  };

  
and then inherit from it in the implementation classes:

  class FullMap : public Map {
  public:
      FullMap();
      // Constructor - initialises main fields.  Constructor body allocates
      // space for array from heap.
  
      ~FullMap();
      // Destructor - must free array space and release referenced objects.
  
  private:
      FullMap( int );
      // Constructor for a known size of map.
  
      Generic *mapArray;
      // The array used to implement the mapping
  
      .... etc etc ....
  }


and provide implementations for the virtual functions:

  // lookupMap
  // Return a pointer to the domain object for given range alpha, or NULL
  Generic FullMap::lookupMap( int alpha ) {
      if (alpha >= mapLength)
         return NULL;
      else
         return (mapArray[ alpha ]);
  }
  

However, the compiler rejects this, saying "lookupMap() is not a member of
FullMap".  I interpret this as saying that I must specifically re-declare the
virtual functions that I am providing implementations for (ie all of them) in
the FullMap class definition, which seems to be borne out by the examples in
Lippman (though I can't see a specific statement to that effect). This obviates
the point of having a separate interface class.

So, collected C++ hackers of the world, is there a standard way of providing
one interface and multiple implementations?

BTW - in case the foregoing is too obscure - what I want is something like the
way that, in SML, I can write a signature MAP and two structures:

    structure FullMap:MAP = struct  ... implementation 1 ... end;
    structure SparseMap:MAP = struct  ... implementation 2 ... end;



Thanks in advance,
Ian.

|Ian Dickinson    HP Labs Bristol (Knowledge Based Programming Dept)   England|
|net:    ijd@hplb.hpl.hp.com       |    "Live simply,                         |
| or:    ijd@hplb.uucp             |          that others may simply live"    |
|    These opinions are mine, and not (necessarily) HP's or anyone else's.    |