C++ Inserting a class into a map container

57,686

Solution 1

First, don't store objects themselves in the map, store pointers to your objects.

Second, you need to give an instance of Scene_Branding to std::make_pair, not the class itself.

EDIT: Here's how you go about storing pointers:

 string CurrentScene = "Scene_Branding";
 map<string, Scene*> Scenes;
 Scenes.insert(std::make_pair("Scene_Branding", new Scene_Branding()));

But, since you asked this type of question, i recommend you read a good c++ book for further grasping of concepts like pointers.

Solution 2

Try:

Scenes.insert(std::make_pair("Scene_Branding", Scene_Branding()));

Solution 3

I think you don't want to do that.

  1. there is no runtime type-mapping in C++, you store objects, not types.
  2. you cannot store polymorphic types in STL containers, use boost::ptr_map instead if it is your wish

So, the "new" code:

class Scene
{
public:
  virtual ~Scene();                  // Virtual Destructor, it's a base class
  virtual Scene* clone() const = 0;  // Polymorphic construction
private:
  // whatever you wish
};

class Scene_Branding: public Scene
{
public:
  virtual Scene_Branding* clone() const { return new Scene_Branding(); }
};

And the new way to store those:

const std::string SceneBrandingKey = "Scene_Branding";

typedef boost::ptr_map<std::string, Scene> scenes_type;

scenes_type Scenes;
Scenes.insert(SceneBrandingKey, new Scene_Branding());

And you can use it thusly:

Scenes["Scene_Branding"].process(); // Note: use '.' not '->'

The nice thing about Boost Pointer Container is that it's been meant for polymorphic types, with exception safety and all, and yet mimics the behavior / interface of the STL so that you are not lost :)

Solution 4

You need pointers in class when use generic map containers else, the result is possible a new object empty of your class... with pointers works!

std::map<std::string, Type*> map_;

Insert

map_["key"] = *Type;

NOTE: if -fpermisive flag to compiler is not set you need pass *Type not const when insert in the map_ container.

Best Regards,

Javier,

Share:
57,686

Related videos on Youtube

Fouf
Author by

Fouf

Updated on June 14, 2020

Comments

  • Fouf
    Fouf about 4 years

    I have a map in C++ and I wish to input my class as the value, and a string as the key. When I try to, I get an error 'Scene_Branding' : illegal use of this type as an expression I get an illegal use of this type as an expression, and I can't seem to find out why. Here is some code.

     string CurrentScene = "Scene_Branding";
     map<string, Scene> Scenes;
     Scenes.insert(std::make_pair("Scene_Branding", Scene_Branding));  //<-- Illegal Error parameter 2
    

    and here is Scene Branding header..

    #ifndef Scene_Branding_H
    #define Scene_Branding_H
    
    #include "Scene.h"
    #include <iostream>
    #include <string>
    
    
    class Scene_Branding : Scene
    {
    public:
     Scene_Branding();
     ~Scene_Branding();
     void Draw();
    };
    
    #endif
    

    and here is Scene header..

    #ifndef Scene_H
    #define Scene_H
    
    #include <iostream>
    #include <string>
    
    class Scene
    {
    public:
     Scene();
     ~Scene();
     virtual void Draw();
    
    };
    
    #endif
    

    and here is there cpp files.

    Scene cpp.

    #include "Scene.h"
    
    Scene::Scene()
    {
    
    }
    Scene::~Scene()
    {
    
    }
    void Scene::Draw(){
     std::cout << "Hey";
    }
    

    Scene_Branding cpp

    #include "Scene_Branding.h"
    
    Scene_Branding::Scene_Branding()
    {
    
    }
    
    Scene_Branding::~Scene_Branding()
    {
    
    }
    
    void Scene_Branding::Draw()
    {
     std::cout << "Drawing from Scene_branding";
    }
    
    • codencandy
      codencandy over 14 years
      both answers are correct in pointing out that you need an instance of Scene_Branding not just the type. one more hint make your base class destructor virtual
    • Admin
      Admin over 14 years
      Do you really mean to use private inheritance?
  • kennytm
    kennytm over 14 years
    Storing objects is fine as long as the object's class is final.
  • Fouf
    Fouf over 14 years
    This works, but the code is not as intended and cout is outputting Hey, and not Drawing from Scene_Branding.. hmm but thanks for the fix.
  • erelender
    erelender over 14 years
    This is because an instance of Scene is stored in the map, not an instance of Scene_Branding. This is called object slicing, briefly it causes you to lose information declared in Scene_Branding. Storing pointers will not cause this issue.
  • Fouf
    Fouf over 14 years
    How would I go about handing it a pointer? I seem to just get errors such as error C2664: 'Scene::Scene(const Scene &)' : cannot convert parameter 1 from 'Scene_Branding (__cdecl *const )(void)' to 'const Scene &'
  • erelender
    erelender over 14 years
    I think OP is a little newbie to be diving into boost yet.
  • Fouf
    Fouf over 14 years
    Aha, I tried this, but I was mistakenly placing Scene_Branding .. anyway, thanks.
  • Dominic.wig
    Dominic.wig over 14 years
    I'm not sure, but IMHO instead of virtual Scene_Branding* clone() const there should be virtual Scene* clone() const ;-)
  • Emile Cormier
    Emile Cormier over 14 years
    It's funny how everybody thinks C++ newbies need to learn to do things the error-prone manual way, before using libraries that make life easier.
  • Emile Cormier
    Emile Cormier over 14 years
    +1 After the OP learns about the pitfalls of manual memory management, he/she will come to appreciate shared_ptr and ptr_container.
  • Emile Cormier
    Emile Cormier over 14 years
    -1 because of slicing bug. I think you didn't see that the OP wants a container of polymorphic objects. :-)
  • erelender
    erelender over 14 years
    Of course, things that make life easier are better but, in order to use high level stuff efficiently, one must understand low level stuff, don't you think? Don't give a lamborghini to a new driver.
  • Matthieu M.
    Matthieu M. over 14 years
    @Dominic: no, it's correct because a Scene_Branding* is convertible to a Scene* (it's called covariant return). It means that by invoking the virtual method you get a Scene* but if you explicitly use the Scene_Branding::clone then you obtain a Scene_Branding* > if you have more type information, you get a more precise type in return :)
  • Matthieu M.
    Matthieu M. over 14 years
    @erelender: I only partially agree. I am not going to delve into template metaprogramming or preprocessor programming yet, it's too soon for the OP. On the other hand, why should I not show easy-to-use libraries ? I don't understand why people keep on teaching about char* manipulations in C++ because std::string are more elaborate when you have strings in just about every other language...
  • erelender
    erelender over 14 years
    @Matthieu: I only partially agree also :). When you teach someone how to use std::string, he only learns how to use std::string. On the other hand teaching char* manupilations allows him to apply the concept of pointer manupilation to other types as well. I think learning a language should be about how stuff works under the hood, not how to use stuff. If one learns how stuff works, others will follow.
  • Ivan Talalaev
    Ivan Talalaev over 5 years
    @kennytm could you clarify a little. What does it mean "as long as object's class is final? You mean final keyword? And why this final will do?
  • kennytm
    kennytm over 5 years
    @IvanTalalaev "final" means there are no subclasses to the Scene class. If there are subclasses then using map<string, Scene> may cause object-slicing. A final class prevents this situation.