Can you create a std::map of inherited classes?

前端 未结 4 1636
醉梦人生
醉梦人生 2021-01-14 12:14

I\'m wondering if it\'s possible to create a map of pointers of inherited classes. Here\'s an example of what I\'m trying to do:

#include 
#inc         


        
相关标签:
4条回答
  • 2021-01-14 12:44

    Yes you can store inherited classes in map, but pointers to them, not objects themselves. Here's a short example (it lacks memory management on pointers)

    #include <iostream>
    #include <string>
    #include <map>
    #include <utility>
    
    using namespace std;
    
    class BaseClass
    {
        string s;
    public: 
        BaseClass() { s = "BaseClass";} 
        virtual void print() 
        {
            cout << s << std::endl;
        }
    };
    
    class Derived1 : public BaseClass
    {
        int i;
    public:
        Derived1() { i = 10; }
        void print() 
        {
            cout << i << std::endl;
        }
    
    };
    
    class Derived2 : public Derived1
    {
        float f;
    public:
        Derived2() { f = 4.3;}
        void print() 
        {
            cout << f << std::endl;
        }
    };
    
    int main()
    {
        map<string, BaseClass*>m;
        m.insert(make_pair("base", new BaseClass()));
        m.insert(make_pair("d1", new Derived1()));
        m.insert(make_pair("d2", new Derived2()));
        m["base"]->print();
        m["d1"]->print();
        m["d2"]->print();
    
        return 0;
    }
    
    0 讨论(0)
  • 2021-01-14 12:48

    First things first:

    template<class myClas>
    map<string, myClass> m;
    

    This is not valid C++ and could only mean something like a template alias, but I believe, that is not what you are looking for.

    Storing polymorphic objects in C++ is complicated by slicing (constructing a value of the base type from a value of a derived type). Dynamic polymorphism can only be handled through references or pointers. You could potentially use std::ref or boost::ref for situations in which the map will only be passed down the callstack, but this requires some care. Often, storing pointers to the base is the way to go: std::map<std::string, base*>. Managing deallocation yourself is rather tedious and either std::map<std::string, std::unique_ptr> or std::map<std::string, std::shared_ptr> are preferred, depending if you need shared semantics or not.

    Basic example. Someone should replace this with something more meaningful.

    #include <memory>
    #include <string>
    #include <map>
    #include <iostream>
    
    class animal
    {
    public:
      virtual ~animal() {};
      virtual void make_sound() const = 0;
    };
    
    class dog : public animal
    {
    public:
      void make_sound() const { std::cout << "bark" << std::endl; }
    };
    class bird : public animal
    {
    public:
      void make_sound() const { std::cout << "chirp" << std::endl; }
    };
    
    int main()
    {
      std::map<std::string, std::unique_ptr<animal>> m;
      m.insert(std::make_pair("stupid_dog_name", new dog));
      m.insert(std::make_pair("stupid_bird_name", new bird));
      m["stupid_dog_name"]->make_sound();
      return 0;
    }
    
    0 讨论(0)
  • 2021-01-14 12:52

    You may have template on classes and functions, but not on instances.

    You should stick to the map to BaseClass*'es.

    0 讨论(0)
  • 2021-01-14 12:58

    Below is the expansion of solution suggested by anton.

    #include <iostream>
    #include <string>
    #include <map>
    #include <utility>
    
    using namespace std;
    
    class BaseClass
    {
        string s;
    
    public: 
        BaseClass() { s = "BaseClass";} 
    virtual ~ BaseClass(){}
    virtual void print()=0;
    };
    
    
    class Derived1 : public BaseClass
    {
        int i;
    public:
        Derived1() { i = 10; }
        void print() 
        {
            cout << i << std::endl;
        }
    
    };
    
    class Derived2 : public Derived1
    {
        float f;
    public:
        Derived2() { f = 4.3;}
        void print() 
        {
            cout << f << std::endl;
        }
    };
    
    class factory
    {
    map<string, BaseClass*>m;
    BaseClass* obj;
    public:
    factory()
    {
    obj=NULL;
    }
    BaseClass* FindType(string s);
    void AddType(string s,BaseClass *obj);
    void deleter();
    ~factory(){cout<<"deleting objects from map"<<endl;
    deleter();
    }
    };
    void factory :: AddType(string s,BaseClass* obj)
    { 
     m.insert(make_pair(s,obj ));
    }
    void factory ::deleter ()
     {
    
       for (auto  pObj = m.begin( );
            pObj != m.end( ); ++pObj) {
    
          delete pObj->second;
       }
    
       m.clear( );  
    
     }
    BaseClass* factory::FindType(string s)
    {
    if(m.find(s)!=m.end())
    {
    
    return  m[s];
    }
    
    return NULL;
    }
    
    int main()
    {   
       BaseClass* obj;
       factory fact_obj; 
       fact_obj.AddType("d1",new Derived1());
       fact_obj.AddType("d2",new Derived2());
       obj=fact_obj.FindType("d1");
       if(obj!=NULL)
          {
        obj->print();
          }
        obj=fact_obj.FindType("d2");
        if(obj!=NULL)
         {
         obj->print(); 
         }
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题