【问题标题】:Can you create a std::map of inherited classes?您可以创建继承类的 std::map 吗?
【发布时间】:2012-01-27 12:07:20
【问题描述】:

我想知道是否可以创建继承类的指针映射。这是我正在尝试做的一个示例:

#include <string>
#include <map>

using namespace std;

class BaseClass
{
    string s;
};

class Derived1 : public BaseClass
{
    int i;
};

class Derived2 : public Derived1
{
    float f;
};

// Here's what I was trying, but isn't working
template<class myClass>
map<string, myClass>m;

int main()
{
    // Add BaseClasses, Derived1's, and/or Derived2's to m here
    return 0;
}

我得到的错误是:

main.cpp(23): 错误 C2133: 'm' : 未知大小
main.cpp(23): error C2998: 'std::map<:string>m' : 不能是模板定义

我知道为什么会出现此错误,但我想知道是否可以创建一个可以容纳不同级别的继承类的映射?如果没有,是否有可能创建某种可以容纳各种班级类型的管理系统?或者我是否必须制作不同的地图/矢量/数组/等。每种类型的课程?

【问题讨论】:

  • 您是否有理由不只是存储BaseClass*s?
  • 是否可以有一张BaseClass*s 的地图,并在保持其功能的同时将Derived1*s 和Derived2*s 添加到其中?我记得之前尝试过类似的事情,但BaseClass*s 的地图看起来像是将我给它的任何东西转换成BaseClass*,不管它最初是什么。
  • 指向派生类的指针可以隐式转换为指向基类的指针(所以是的),但您必须有办法确定指针指向的实例的派生类型,那么你必须将基指针转换为派生指针才能使用任何派生函数。
  • @user1114983,您将只能使用BaseClass 中声明的方法(无需使用强制转换),但除此之外不会丢失任何功能。

标签: c++ inheritance stdmap


【解决方案1】:

是的,您可以将继承的类存储在映射中,但可以存储指向它们的指针,而不是对象本身。这是一个简短的示例(它缺少指针的内存管理)

#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;
}

【讨论】:

  • 请问myClass 在哪里以及如何声明用于地图?
【解决方案2】:

第一件事:

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

这不是有效的 C++,只能表示 template alias 之类的意思,但我相信,这不是您想要的。

在 C++ 中存储多态对象因切片(从派生类型的值构造基类型的值)而变得复杂。动态多态性只能通过引用或指针来处理。您可能会使用std::ref 或boost::ref 来处理地图只会向下传递到调用堆栈的情况,但这需要小心。通常,存储指向基址的指针是要走的路:std::map&lt;std::string, base*&gt;。自己管理解除分配相当繁琐,首选std::map&lt;std::string, std::unique_ptr&gt; 或std::map&lt;std::string, std::shared_ptr&gt;,具体取决于您是否需要共享语义。

基本示例。有人应该用更有意义的东西来代替它。

#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;
}

【讨论】:

  • 您的示例很好,除了您使用的是 C++11 的一部分 std::unique_ptr 并且目前还没有被广泛使用。我不会向 C++ 世界的新手推荐新的标准功能。
  • @Anton 我反其道而行之。到目前为止,每个主要实现都支持unique_ptr,并且没有充分的理由让他学习旧的方法。除了维护,他看到这样的代码并用现代成语替换它。
  • 好吧,在一个完美的世界里,每个人都会使用最新版本的技术。但事实是——在现实生活中,你受到公司规则或其他方式限制的情况太多了。当你开始在一家公司工作时,他们不会给你一个新的 VisualStudio 或最新的 gcc 编译器,这并不是理所当然的。在这种情况下,将您的知识降级到现有环境是一件非常痛苦的事情。当然,这不适用于为自己或某些开源项目编写代码
  • @Anton 你的观点是有道理的,但是反对它的方式有很多种。在这里讨论这个没有实际意义。只需在您的答案中添加一个释放内存的示例,他就会知道他需要的一切。
  • 我知道这是古老的,但我在这里。是否可以使用引用而不是指针来做到这一点?我真的很好奇。我想知道引用是否会使内存管理更容易或更快。
【解决方案3】:

您可能在类和函数上有模板,但在实例上没有。

你应该坚持到BaseClass*'es的地图。

【讨论】:

    【解决方案4】:

    以下是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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-25
      • 2020-05-09
      • 1970-01-01
      • 2018-02-08
      相关资源
      最近更新 更多