[prog] C++: storing objects of different type in a std::map

Kathryn Hogg kjh at flyballdogs.com
Tue Sep 21 08:27:03 EST 2004


Riccarda Cassini said:
> 1) Why does the baseClass ever need to be instatiated at all, in the
> version that I tried originally?  Does the map declaration
>
>     std::map<std::string, baseClass> dispatch;
>
> actually create an object of type baseClass?  If so, what is it for?

You have declared a map from type string to type baseClass.  The map is
storing objects of type baseClass indexed by keys of type string.

So when you do something like

dispatch["mode-A"] = a0;

what is happening (logically, implementations may differ) is that

  1. the map<> allocates a node that is a struct containing the key (type
     std::string) and the object (type baseClass):

     i.e. struct map<std::string, baseClass>::node {
              std::string key;
              baseClass   t;
              ..... ;   // other bookkeeping things that the map needs
           }

  2. dispatch["mode-A"] will find the appropriate node, and return a
     reference to the "t" member of the node.

     so this is analogous to having
     baseClass &tp  = dispatch["mode-A"];
     tp = a0;

  3. So now we're down to an assignment of a0 to an object of type
     baseClass;

     baseClass & = classA;

     when these types of assignments happen, the compiler will call
     baseClass::operator = (const baseClass &)  since that is the best
     fit (objects of type classA are in fact also objects of baseClass)

     for example.

      class book { ....};
      class hardcover: public book { ... };


    4. Obviously, since the object being assigned to is a baseClass, it
       cannot store any information that the derived class may define.  So
       in effect, assigning a derived class to its base class truncates the
       copy.

>
> 2) Why is it that the pointers ClassA* and ClassB* are not being cast
> to baseClass*,

Yes they are.  A "ClassA *" and "ClassB *" are instances of "baseClass *"
The polymorphic types in C++ are pointers and references.  In languages
like Java or Smalltalk all objects are passed by reference.  There is no
pass by value for objects.  So in smalltalk or java, it would be more like
saying
     std::map<std::string, baseClass &>

Of course, these languages have different models for the lifetime of
objects and you don't have to worry about them going out of scope.

> while the derived objects themselves are obviously being
> cast to type baseClass when being put in the map?

They aren't being cast.  A map<std::string, baseClass> store objects of
type baseClass.  Thus each node allocates storage for a baseClass.  When
you put a derived object in the map, a copy of the object is placed in the
node.  Since the node stores baseClass, you effectively truncate the right
hand side in the copy.

> I mean, a pointer of
> type ClassA* is different from a pointer of type baseClass*,

No the C++ language explicitly says that a "derived *" *IS A* "base *".
Think about the book example above.

> just as the type ClassA is not the same as type baseClass - so what's the
> logic behind treating objects and pointers to objects differently?

It all boils down to pass-by-value vs pass-by-reference.  I recommend
reading a good C++ book.  I'd recommend one but my references are a little
bit crusty (been programming in C++ for 17 years)

-- 
Kathryn
http://womensfooty.com



More information about the Programming mailing list