1

I have the class Person:

class Person {
public:
    int Age;
    int ID;
};

And I have 2 classes: Adult and Child that inherit Person:

class Child : Person{
public:
    Child();
    void print_ms_child(){
        cout << "I'm an child";
    }
};

class Adult : Person{
public:
    Adult(); 
    void print_ms_Adult(){
        cout << "I'm an adult";
    }
};

I want to declare a Person Object

int main() {
    Person my_Person;
    my_Person.Age = 10;
    my_Person.ID = 013272;

And then use conditions to set its type.

    if(my_Person.Age > 18){
        my_Person = new Adult(); // this won't work
    }
    else{
        my_Person = new Child(); // this won't work
    }

I suppose it it's posible but I don't know the right syntax for doing it (How do I do that?). (Sorry for posting code that won't even compile)

But also, I want to change from Child to Adult in case the Age changes (I'm not even sure that's possible).

    my_Person.Age = 21;
    my_Person = new Adult(); // this won't work
Ivan
  • 1,352
  • 2
  • 13
  • 31
  • 1
    Does this answer your question? [Why doesn't polymorphism work without pointers/references?](https://stackoverflow.com/questions/15188894/why-doesnt-polymorphism-work-without-pointers-references) – walnut Jan 25 '20 at 16:15
  • 1
    Since you are using `new` which returns a *pointer* to an object, not the object itself, it seems to me that you simply intended `my_Person` to be a `Person*`, not `Person`. Otherwise, how could `new` work with it in the first place, inheritance and polymorphism aside? Also note that you need to make a *virtual* interface (especially a `virtual` destructor) in order to use the derived classes through the base class pointer. – walnut Jan 25 '20 at 16:17
  • 1
    Also, you should not use `new` in modern C++. You can use `std::make_unique` together with `std::unique_ptr` instead, which will correctly `delete` the pointer for you, so you don't forget it or accidentally double-delete. – walnut Jan 25 '20 at 16:22
  • If your classes are really this simple, why don't you just have a `bool isAdult() const;` member function of `Person` and not use the derived classes? – 1201ProgramAlarm Jan 25 '20 at 16:27
  • @1201ProgramAlarm this is just an example to, I want to make this to more complicated classes – Ivan Jan 25 '20 at 16:53

2 Answers2

1

I would first define your class Person like this instead:

class Person {
    int Age;
    int ID;
protected:
   Person(int age, int id): Age{age}, ID{id} {}
public:
   virtual ~Person() = default;
};

That is, Person's constructor is made protected so that a class outside the hierarchy can't create a Person object, and its destructor is made virtual to make it suitable as a base class for a polymorphic type.

Then, both Child and Adult publicly inherit from Person, as you already have them. Their constructors end up calling Person's constructor with the same parametrization their constructors receive:

class Adult: public Person {
public:
   Adult(int age, int id): Person(age, id) {}
   // ...
};

class Child: public Person {
public:
   Child(int age, int id): Person(age, id) {}
   // ...
};

Finally, for creating objects that derived from Person, I would create the factory function below:

std::unique_ptr<Person> create_person(int age, int id) {
   if (age < 18)
      return std::make_unique<Child>(age, id);
   else
      return std::make_unique<Adult>(age, id);
}

This factory function creates a Child object if the to-create person's age is under 18. Otherwise, it creates an Adult object. This – determining the type of the object to create – is done at run time.


EDIT: You wondered how a Child object could become an Adult object after its age has reached 18 years old.

I would suggest making the state of a Person object immutable so that a fresh new object has to be created every time the age of a person is increased. This way, creating a new object from an existing one will be the only way to grow a Person's age and, at that moment, you will have the control to decide whether to create a Child or Adult object based on the new age.

For doing this, first, qualify the Age data member in Person as const (you can do the same with ID). Then, define the following Person's member function which always creates a new object (with the same ID) resulting from increasing a Person's object Age by one:

std::unique_ptr<Person> Person::increase_age() const {
   return create_person(Age + 1, ID);
}

As you see, it delegates the creation of the object to the factory function, create_person(), already explained above. This member function can be called on both Child and Adult objects since it inherits from Person.

JFMR
  • 23,265
  • 4
  • 52
  • 76
  • 1
    Thank you! this is very useful. But then I wonder if, once we have an Object Child, can we change it's age and therefor it should be an Adult – Ivan Jan 25 '20 at 16:52
  • 1
    @Ivan you could, for example, create a member function in `Child` called `increase_age()`. Such a function could return an `std::unique_ptr` as well – a new object resulting from the age increment. This would follow the same principle as the *factory function above*: if the new age is still lower than 18, then you create a `Child`, otherwise, an `Adult`. In both cases, you use the new age and the `ID` of the current object. I hope it helps – JFMR Jan 25 '20 at 16:56
  • 1
    @Ivan I've edited the answer with the information I've explained to you. I hope it is clear now. – JFMR Jan 26 '20 at 10:13
0

You cannot change the type of a variable after its declaration. C++ is a statically typed language. my_person is a Person. You cannot change that.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70