Способ преодоления нарезки объектов

Есть ли способ отойти, преодолеть нарезку объектов без использования нового ключевого слова в качестве параметра для работы? У меня есть базовый объект

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 = new Person(a);
            m[ name ] = one;
        }
        void print(){
            for( auto &x: m )
                 x.second -> getInfo()
        }
    protected:
        string name;
        int age;
       map< string , Person*> m;
    };

Производные объекты

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

И пытаясь вызвать его, например

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

Из-за нарезки объекта он печатает

"Человек..."

Я пробовал использовать unique_ptr и получил тот же результат. Я попытался объявить copy function, например

vitual clone() const{ return new Person(*this);}

в базовом классе

и в производных классах я объявил

Kid* clone() const{ return new Kid(*this);}
Adult* clone() const{ return new Adult(*this);}

и отредактировал функцию добавления.

    void add( string name , Person a){
        Person *one = a.clone();
        m[ name ] = one;
    }

И я все еще был поражен скользящим предметом. Я пробовал разные вещи/подходы/методы, и все они привели к нарезке объектов.

Есть ли способ создать такую ​​​​вещь (карту, которая содержит производные классы базового класса) без использования ключевого слова new в аргументе функции, например

Person one("bla",5);
one.add("asd", new Kid("one",15))

Спасибо за помощь.

// Текущее состояние кода

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 , const Person &a){
            Person *one = a.clone();
            m[ name ] = one;
        }
        void print(){
            for( auto &x: m ){
                 x.second -> getInfo();
                 cout << endl;
            }
        }
         virtual Person* clone() const{ return new Person(*this);}

    protected:
        string name;
        int age;
        map< string , Person*> m;
    };

class Kid : public Person{
    public:
        Kid(string name, int age):Person(name,age){};
        virtual void getInfo( ){
            cout << "Kid " << name << " " << age;
        }
        Kid* clone() const{ return new Kid(*this);}
    };
 class Adult : public Person{
    public:
        Adult(string name, int age):Person(name,age){};
        virtual void getInfo( ){
            cout << "Adult " << name << " " << age;
        }
        Adult* clone() const{ return new Adult(*this);}
    };

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

person Darlyn    schedule 30.04.2016    source источник
comment
что вы имеете в виду с использованием нового ключевого слова в качестве параметра для работы ?? Если вы хотите избежать нарезки объектов, просто передайте указатель или ссылку....   -  person 463035818_is_not_a_number    schedule 30.04.2016
comment
Не могли бы вы показать пример? Я пытался заставить его работать в течение нескольких часов, и я безуспешно пытался передать как ссылку, так и указатель.   -  person Darlyn    schedule 30.04.2016


Ответы (3)


Измените свою функцию add(), чтобы она принимала ее параметр по ссылке:

void add( string name , const Person &a){
    Person *one = a.clone();
    m[ name ] = one;
}

Вы нарезаете объект, когда передаете его по значению. Это копирует и нарезает его. Вместо этого вам нужно передать параметр как ссылку.

Все ваши clone() методы уже постоянны. Хороший.

person Sam Varshavchik    schedule 30.04.2016
comment
он по-прежнему получает нарезанную печать только Person.. - person Darlyn; 30.04.2016
comment
Вы действительно не показали, как вы объявили свои методы clone(). Вы только перефразировали. Таким образом, любой ответ будет в лучшем случае предположением. В любом случае для этого и нужен отладчик. Пройдитесь по коду, строка за строкой, и посмотрите, метод clone() какого объекта вызывается. - person Sam Varshavchik; 30.04.2016
comment
Я написал, как объявил функцию clone(), в моем вопросе есть целое объявление. - person Darlyn; 30.04.2016
comment
Только как дополнительный комментарий, перефразированный, после того, как вы показали свой код без него. - person Sam Varshavchik; 30.04.2016
comment
Я обновил вопрос для всего кода, как это выглядит - person Darlyn; 30.04.2016
comment
Не похоже. Кроме того, вы неправильно написали виртуальный в своем предполагаемом коде. Но в любом случае, как я уже сказал: используйте отладчик. Знание того, как использовать отладчик, является обязательным навыком для любого, кто хочет стать опытным разработчиком C++. Пройдитесь по своему коду внутри функции add(), которая принимает параметр по ссылке, перейдите к вызову clone() и посмотрите, какой метод clone() класса вызывается. Если вы утверждаете, что получили базовый класс, начните заново и установите точку останова в конструкторе копирования базового класса, чтобы определить, когда и почему он был нарезан. Вот ваш ответ. - person Sam Varshavchik; 30.04.2016
comment
@trolkura, и, пожалуйста, не редактируйте свой вопрос, чтобы исправить проблемы, о которых вы изначально просили. Это делает недействительным уже данный ответ, делает ваш вопрос бессмысленным для будущих читателей. - person 463035818_is_not_a_number; 30.04.2016

измените свой add(), чтобы получить аргумент Person с помощью *

void add( string name , Person* a ){
    m[ name ] = a;
}

измените способ передачи объекта функции add() объектам, размещенным в свободном хранилище.

Определите свой собственный конструктор копирования в классе Person

person george_ptr    schedule 30.04.2016
comment
Что вы подразумеваете под этим, разве недостаточно функции clone()? Не могли бы вы привести пример, пожалуйста? - person Darlyn; 30.04.2016
comment
Такой API, как void add(std::unique_ptr<Person>), кажется, напрашивается сам собой. - person Kerrek SB; 30.04.2016

Если вы не хотите, чтобы ваши объекты были нарезаны, вам просто нужно пройти по ссылке или указателю:

struct Foo { 
    virtual void print() const {std::cout << "FOO" <<std::endl;} 
};
struct Bar : Foo { 
    void print() const {std::cout << "BAR" <<std::endl;} 
};

void slicingFunc(Foo foo){ foo.print(); }
void nonSlicingFunc(const Foo& foo) { foo.print(); }


int main() {
    Bar b;
    slicingFunc(b);    // prints FOO
    nonSlicingFunc(b); // prints BAR
    return 0;
}
person 463035818_is_not_a_number    schedule 30.04.2016