派生函数的映射

时间:2016-04-30 13:06:15

标签: c++ inheritance dictionary polymorphism

我有Base和Derived类 基地:

class Person{
public:
    Person(string name , int age ){
        this -> name = name;
        this -> age  = age;
    }
    virtual void getInfo(){
        cout << "Person " << name << " " << age;
    }

protected:
    string name;
    int age;
};

派生:

class Kid : public Person{
public:
    Kid(string name, int age):Person(name,age){};
    virtual void getInfo( ){
        cout << "Kid " << name << " " << age;
    }
};
 class Adult : public Person{
    public:
        Adult(string name, int age):Person(name,age){};
        virtual void getInfo( ){
            cout << "Adult " << name << " " << age;
        }
    };

当我做

之类的事情
map<string ,Person*> m;
Person *one;
Person *three;
Kid two("Mathew",15);
Adult four("JOhn",55);
three = &four;
one = &two;
m["first"] = one;
m["second"] = three;
for( auto &x : m )
   x.second-> getInfo();
return 0;

它很好地打印信息,因为它应该//&#34;成人&#34;成人班和&#34;孩子&#34;为孩子班

然而,当我编辑类并将地图移动到基类时。例如,创建Add方法。

 class Person{
    public:
        Person(string name , int age ){
            this -> name = name;
            this -> age  = age;
        }
        virtual void getInfo(){
            cout << "Person " << name << " " << age;
        }
        void add( string name , Person a){
            Person *one = &a;
            m[ name ] = one;
        }
        void print(){
            for( auto &x: m )
                 x.second -> getInfo()
        }
    protected:
        string name;
        int age;
       map< string , Person*> m;
    };



   Person one("John", 25);
   one.add("first",Kid("Mathew",15));
   one.add("second",Adult("Leo",55));
   one.print();

它抛出了seg故障,为什么会发生这种情况?它与使用方法基本相同。是什么导致了seg故障?有办法解决它吗?

//编辑

我尝试使用unique_ptr重新映射地图

map< string ,  unique_ptr<Person>> m;
   AddField (string name , Person   a ){

            m[name] = ( unique_ptr<Person> (a)); 
            return *this;
        }

  properties[name] = unique_ptr<Person> ( new Person( a ));

 AddField (string name , Person   a ){

        CData *one = unique_ptr<Person>(new Person(a));
        m[name] = one ;
        return *this;
    }

我对unique / share ptr没有经验。 这扔了

  

'std :: unique_ptr'到'人*'

2 个答案:

答案 0 :(得分:2)

首先,让我们了解地图实际存储的内容:

map< string , Person*> m;

此映射将字符串绑定到Person*,这是指向某个人的内存地址。地图实际上并不存储人员实例,只存储其内存地址。

现在让我们分析你的两种情况。

 map<string ,Person*> m;

// Allocating space for two memory addresses on the stack:
Person *one;
Person *three;

// Creating two instances on the stack:
Kid two("Mathew",15);
Adult four("JOhn",55);

// Setting the pointers to the memory addresses of the instances on the stack:
three = &four;
one = &two;

m["first"] = one;
m["second"] = three;
for( auto &x : m )
   x.second-> getInfo();
return 0;

// End of the function: now all objects are destroyed in reverse order.

实例twofour存在于堆栈中,并在范围的末尾(return 0;之后)被销毁。获取内存地址并将其存储到onethree中是很好的,因为指针将比twofour更长。

Person one("John", 25);

// Creating a Kid instance without a name (temporary).
// The Kid instance goes out of scope immediately and is destroyed:
one.add("first",Kid("Mathew",15));

// Creating an Adult instance without a name (temporary).
// The Adult instance goes out of scope immediately and is destroyed:
one.add("second",Adult("Leo",55));

one.print();

这里的问题是您正在创建的实例过早销毁。您需要正确管理它们的生命周期,以确保您插入到映射中的内存地址不会超过指向内存位置中的数据。

另一个主要问题是您按值接受add的{​​{1}}参数。这将创建传递的实例的副本。

Person a

您应该将// Copy the passed instance: void add( string name , Person a){ // Take memory address of the copied instance: Person *one = &a; m[ name ] = one; // The copied instance is destroyed here! } 作为参考,以避免副本和object slicing

a

在更正void add( string name , Person& a){ m[ name ] = &a; } 的签名后,这是一个有效的示例:

a

答案 1 :(得分:1)

我试图解决你的问题,我想出了一个初始版本。我并不满意。

#include<iostream>
#include<map>
#include<memory>
#include<string>

/* used to simplify example code (not a good 
   idea in production code especially header files)
*/
using namespace std;

class Person
{
    public:
    virtual void getInfo() const = 0;
    virtual ~Person()
    {};

    void add(std::shared_ptr<Person> a)
    {
        m_[a->name_] = a;
    }

    void print() const
    {
        getInfo();
        for( auto &x: m_ )
             x.second->getInfo();
    }

    protected:
    Person(const string& name, int age)
        : name_(name), age_(age)
    {}    

    string name_;
    int age_;
    map<string , std::shared_ptr<Person>> m_;
};

class Kid : public Person
{
    public:
    Kid(const string& name, int age)
        : Person(name, age)
    {};

    virtual void getInfo() const override
    {
        cout << "Kid " << name_ << " " << age_ << '\n';
    }
};

class Adult : public Person
{
    public:
    Adult(const string& name, int age)
        : Person(name, age)
    {};

    virtual void getInfo() const override
    {
        cout << "Adult " << name_ << " " << age_ << '\n';
    }
};


int main()
{
    auto a = Adult("steve", 35);

    auto k1 = make_shared<Kid>("ben", 7);
    auto k2 = make_shared<Kid>("emily", 12);

    a.add(k1);
    a.add(k2);

    a.print();

}

我使用shared_ptr,因为我猜测您可能希望从地图中检索这些Person并从 getter 调用中返回它们。所以在这种情况下unique_ptr毫无意义。

我认为这个版本给调用者带来了太多的负担来创建shared_ptr。虽然很难提出替代方案,但却不知道你打算做什么。