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

Kathryn Hogg kjh at flyballdogs.com
Mon Sep 20 20:22:49 EST 2004


Riccarda Cassini said:

> OK, fine, makes sense.  Next, I thought that, maybe, adding some common
> base class that all objects are derived from might help (specifying the
> base class as the type to store in the map).

Yep, that is the correct path to take.

 This is something I could
> add to the existing source without too much fuss, as the classes are
> rather similar, anyway.  So, I tried:
>
> #include <string>
> #include <iostream>
> #include <map>
>
> class baseClass
> {
>     public :
>         virtual void update() = 0;
> };

Looks good.

>
>
> class ClassA : public baseClass
> {
>     public :
>         ClassA(int num = 0) { id = num; }
>         void update() {
>             std::cout << "updating A (id=" << id << ")\n";
>         }
>     private:
>         int id;
> };
>
> class ClassB : public baseClass
> {
>     public :
>         void update() {
>             std::cout << "updating B\n";
>         }
> };

Looks good here too.

> int main()
> {
>     std::map < std::string, baseClass > dispatch;

Ok, here's the problem.  The compiler is complaining because you can't
instantiate objects of type baseClass because of the pure virtual function
update.

And before you take take the "=0" off the the declaration, you should
realize that the compiler did a very good thing.

If you could use a baseClass, thats all you will have in the map.  Any
object of a derived class will be downgraded/truncated to its base class
component.

What you want to do is store an object that can be of type baseClass or
any of its descendents.  C++ provides two constructs for this: pointers
and references.

The simplest methos would be to change the map to

   std::map<std::string, baseClass *> dispatch;

and then allocate heap objects to put in the map.


>
>     ClassA a0, a1(1), a2(2);
>     ClassB b;
>
>     dispatch["mode-A"]   = a0;
      dispatch["mode-A"] - new ClassA;

>     dispatch["mode-A-1"] = a1;
      dispatch["mode-A-1"] = new ClassA(1);

>     dispatch["mode-A-2"] = a2;
>     dispatch["mode-B"]   = b;
>
>     dispatch["mode-A"].update();
>     dispatch["mode-A-1"].update();
>     dispatch["mode-A-2"].update();
>     dispatch["mode-B"].update();
> }


> When I supply some dummy implementation of update() in the base class,
> it compiles fine, but then that function is always being called,
> independently of which object types I store in the map, i.e. when I
> rewrite the above baseClass definition as

Correct as I explained above, when you insert objects into the map, you
are storing objects of exactly type baseClass.

>
> class baseClass
> {
>     public :
>         void update() {
>             std::cout << "updating base\n";
>         }
> };

You would still have wanted  "virtual void update()" if you intended to
override the implementation in derived classes.

> So, my question is, how would an experienced C++ programmer approach
> the issue?  Would using templates help? If yes, how?
> Please be gentle... I just started dabbling around in C++

The way you attempted to go about it is reasonable.

-- 
Kathryn
http://womensfooty.com



More information about the Programming mailing list