2016-04-30 78 views
2

我有父类:地图存储派生的对象

class Data 
{ 
    public: 
     Data (void) { } 
     Virtual int Size (void) 
     { 
      return 100; 
     } 
    protected: 
     map<string, Data*> m; 

}; 

类从类继承的数据:

class Struct : public Data 
{ 
    public: 
     Struct (void) { } 
     Struct & Add (const string & name, Data x) 
     { 
      Data * tmp = new Data (x); 
      m[name] = tmp; 
      return *this; 
     } 
     void Print (void) 
     { 
      for (const auto & tmp : m) 
       cout << tmp . first << " " << tmp . second -> Size() << endl; 
     } 
}; 

class IntData : public Data 
{ 
    public: 
     IntData (void) { } 
     int Size (void) 
     { 
      return 4; 
     } 
}; 

class DoubleData : public Data 
{ 
    public: 
     DoubleData (void) { } 
     int Size (void) 
     { 
      return 8; 
     } 

}; 

主:

int main (void) 
{ 
    Struct a; 
    a . Add ("Integer",IntData()); 
    a . Print(); 
    return 0; 
} 

Current output : Integer 100 
Expected output : Integer 4 

我想创建一个映射,它可以存放从Data类派生的各种类型的对象。但是当我想调用方法大小存储对象在映射(在这种情况下IntData)应该返回4它总是从父类数据返回值。我该如何解决这个问题?

+0

你'Data'类需要虚析构函数。但更重要的是,多态只有在引用或指针作为参数时才起作用。你的'Add'函数传递一个对象。谷歌“对象切片”。另外,发布真正的代码,因为'虚拟'不是关键字。 – PaulMcKenzie

回答

4

有你的问题:

 Data * tmp = new Data (x); 

你把到地图的实际指针是Data父类的一个实例。您正在拷贝构建一个新的Data父类的实例,该实例来自您按值传递的参数作为参数。

您需要更改这个整体功能:

Struct & Add (const string & name, Data *x) 
    { 
     m[name] = x; 
     return *this; 
    } 

,主叫方现在是负责构建任何子类的新实例:

a . Add ("Integer",new IntData); 

那么,这将作为您预期。

当然,这种方法带来了内存泄漏等各种问题,所以你最好使用std::shared_ptr。但是,这将是一个不同的问题...

+0

是的感谢您的答案,它现在正常工作,但有没有办法如何做到这一点,而不通过'新的IntData',只需通过'IntData()'就像我在我的代码中? – kvway

+0

@kvway请阅读我上面的评论。答案是“否” - 多态性与引用和指针一起工作。通过值传递一个对象切片。 – PaulMcKenzie

+0

@kvway如果'Data'有一个虚拟的'clone'函数,'Add'通过引用接受'Data',那么它可能是的,是的。但那你为什么想要? –

1

我已经为你重写你的代码。

#include <unordered_map> 
#include <memory> 
#include <iostream> 

class Data { 
    public: 
     virtual ~Data(){} 
     virtual int Size() = 0; 
}; 

class Struct : public Data { 
      std::unordered_map<std::string, std::unique_ptr<Data>> m; 
    public: 
     Struct& Add(const std::string& name, std::unique_ptr<Data> x) { 
      m[name] = std::move(x); 
      return *this; 
     } 
     void Print() { 
      for(const auto& tmp : m) 
       std::cout << tmp.first << " " << tmp.second->Size() << "\n"; 
     } 
     int Size() override { 
      int sum = 0; 
      for (const auto& tmp : m) 
       sum += tmp.second->Size(); 
      return sum; 
     } 
}; 

class IntData : public Data { 
    public: 
     int Size() override { return 4; } 
}; 

class DoubleData : public Data { 
    public: 
     DoubleData() { } 
     int Size() override { return 8; } 
}; 

int main() { 
    Struct a; 
    a.Add("Integer", std::make_unique<IntData>()); 
    a.Print(); 
} 

Your welcome.

+0

请添加一些解释,而不仅仅是代码,使这个答案具有很高的价值 –