1

Is there a way how to step away , overcome object slicing without using new keyword as paramater to function? I have base object

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

Derived objects

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

And trying to invoke it such as

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

Due to object slicing it prints

"Person..."

I have tried using unique_ptr and ended up with same result. I tried declaring copy function such as

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

in base clase

and in derived classes i declared

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

and edited add function.

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

And i was still strucked down by a object slicind. I have tried various things/approaches/methods and all led to object slicing.

Is there a way how to create such thing ( map that holds derivec classes of base class ) without using new keyword in the argument of function e.g

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

Thanks for help.

// Current state of the code

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();
}
Darlyn
  • 4,715
  • 12
  • 40
  • 90
  • 1
    what do you mean with "using new keyword as paramater to function" ?? If you want to avoid object slicing simply pass a pointer or reference.... – 463035818_is_not_an_ai Apr 30 '16 at 18:05
  • Could you please show an example? I have been trying to make it work for a few hours n and i tried passing both reference and pointer without success – Darlyn Apr 30 '16 at 18:13

3 Answers3

2

Change your add() function to accept its parameter by reference:

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

You are slicing the object when you're passing it by value. That copies and slices it. You need to pass the parameter as a reference, instead.

All your clone() methods are already constant. Good.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • it still get sliced printing only "Person.." – Darlyn Apr 30 '16 at 18:18
  • You didn't really show how you declared your clone() methods. You only paraphrased it. So, any answer would be a guess, at the best. In any case, this is what a debugger is for. Step through your code, line by line, and see which object's clone() method gets invoked. – Sam Varshavchik Apr 30 '16 at 18:21
  • I did wrote how i declared the clone() function , there is a whole declaration in my quetion. – Darlyn Apr 30 '16 at 18:21
  • Only as an additional comment, paraphrased, after you showed your code without it. – Sam Varshavchik Apr 30 '16 at 18:22
  • I have updated the question for whole code , how it looks like – Darlyn Apr 30 '16 at 18:23
  • Doesn't appear to be. Besides, you misspelled "virtual", in your alleged code. But, whatever the case may be, like I said: use a debugger. Knowing how to use a debugger is a required skill for anyone who expects to become a skilled C++ developer. Step through your code, inside the add() function, that takes a parameter by reference, step into the clone() call, and see which class's clone() method gets invoked. If you claim you get a base class, start again, and set a breakpoint on the base class's copy constructor, to trap when and why it gets sliced. There's your answer. – Sam Varshavchik Apr 30 '16 at 18:25
  • @trolkura and please dont edit your question to fix problems you were originally asking for. This invalidates already given answer, makes your question pointless for future readers. – 463035818_is_not_an_ai Apr 30 '16 at 18:29
0

change your add() to get the Person argument by *

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

change how you pass the object to the add() function to objects allocated on the free store.

Define your own copy constructor in Person class

george_ptr
  • 558
  • 6
  • 17
0

If you dont want your objects to get sliced, you simply have to pass by reference or pointer:

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;
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185