OOP: Is this polymorphism?

My lack of trying to understand these concepts.

- the use of the virtual keyword
- l've heard is more common to use pointers when manipulating classes
- also l've heard the 'pure virtual functions'

l dont get the concepts very clear; Plus my question is... is this a polymorphism? l didn't use the virtual, or even pointers. (Inheritance->) l even override my methods. l just added more functionality. this is my code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Person {
   private:
      string name;
      int age;
   public:
      void  setNameAge (string _name, int _age) {
         name = _name;
         age = _age;
      }
      void greet () {
         printf ("\n- Hi my name is '%s'", name);
         printf (" I have '%d' years old", age);
      }
};
class Teacher: public Person {
   private:
      string course;
   public:
      void setCourse (string _course) {
         course = _course;
      }
      void greet () {
         Person::greet();
         printf (" and I'll teach you the course of '%s'.", course );
      }
};

class Student: public Person {
   private:
      char grade;
   public:
      void setGrade (char _grade) {
         grade = _grade;
      }
      void greet () {
         Person::greet();
         printf (" and I come from grade %c.", grade);
      }
};

int main () {
   Person unknown;
   Teacher jackfruit;
   Student pineapple;

   unknown.setNameAge("Unknown", 10);
   unknown.greet();

   jackfruit.setNameAge ("Jack Fruit", 213);
   jackfruit.setCourse ("Object oriented programming");
   jackfruit.greet();

   pineapple.setNameAge ("Pineapple", 179);
   pineapple.setGrade ('C');
   pineapple.greet();

   return 0;
   getch();
}



- Hi my name is 'Unknown' I have '10' years old
- Hi my name is 'Jack Fruit' I have '213' years old and I'll teach you the cours
e of 'Object oriented programming'.
- Hi my name is 'Pineapple' I have '179' years old and I come from grade C.
Last edited on
an example of a polymorph would be

pineapple = unknown; //these are not of the same type, but the compiler figures it out.

which you did not do here.



Last edited on
Not quite. You already know that a Student is a Student.

What if we would know?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <vector>

// your class definitions

int main () {
   Person unknown;
   Teacher jackfruit;
   Student pineapple;

   unknown.setNameAge("Unknown", 10);

   jackfruit.setNameAge ("Jack Fruit", 213);
   jackfruit.setCourse ("Object oriented programming");

   pineapple.setNameAge ("Pineapple", 179);
   pineapple.setGrade ('C');

   // treat everyone as a Person
   std::vector<Person*> team { &unknown, &jackfruit, &pineapple };
   for ( auto x : team ) {
     x->greet();
   }
   return 0;
}

Our 'team' has three Person members, or more properly points to three members. We can greet them all and they all respond the same way; the Person way. That is "monomorphic".


If we change the greet() into a virtual function, then the behaviour changes. A Person that is actually Student, will greet like a student. All Persons no longer behave the same way.

The point is that if objects are created during runtime dynamically, we cannot/should not need to know their actual type, but they should still behave appropriately.
No. It's encapsulation.

OOP involves manipulating things without knowing their specific type. For example,
1
2
3
4
5
6
7
8
9
10
11
class Person
{
    std::string name;
    int age;
public:
    Person(const string& _name, int _age) : name(_name), age(_age) {
    }
    std::ostream& greet (ostream& os) const {
        os << "\n- Hi my name is '" << name <<" I am " << age << " years old";
    }
};


You can then write code like:
1
2
3
4
5
6
7
8
int main()
{
    std::ofstream file("/tmp/out");

    Person barbie("Barbie", 30);
    barbie.greet(std::clog);
    barbie.greet(file);
}


Person.greet() can be call with any kind of ostream, not just std::cout, but a file, or network, or an in-memory stream. That's polymorphism in action. And to do that, you need to refer to the object via some kind of indirection, in this case a reference, but a pointer is the alternative.
Is this polymorphism?

No.
wikipedia wrote:

Polymorphism is the provision of a single interface to entities of different types.

https://en.wikipedia.org/wiki/Polymorphism_(computer_science)
You have declared three different types using inheritance, but you don't have a single interface to them.

the use of the virtual keyword

The virtual keyword is key to providing a single interface. If you declare greet() virtual in the base class (Person), then create an Student or Teacher object and call Person's greet() function, the greet() function of the derivived class will be called.

I've heard is more common to use pointers when manipulating classes

It is common to use pointers to classes when using polymorphisim.

l've heard the 'pure virtual functions'

A "purge virtual" function has no implementation in the base class and is indicated by =0 in the function declarations. A pure virtual function must be overridden in each derived class.
1
2
  //  In class Person
  virtual void greet () = 0;


A few comments on your code:

Lines 11,12,14,24,37: Don;t mix C and C++ I/O. Use cout, not printf.

Lines 11,24: You can;t use a std::string in a printf statement. printf does not know how to print a std:;string.

Line 58: This line will never be reached.

Your main with polymorphism.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main () 
{   Person *    person; 
    Teacher *   jackfruit;
    Student *   pineapple;

    jackfruit = new Teacher;
    jackfruit->setNameAge ("Jack Fruit", 213);
    jackfruit->setCourse ("Object oriented programming");
    person = jackfruit;
    person->greet();

    pineapple = new Student;
    pineapple->setNameAge ("Pineapple", 179);
    pineapple->setGrade ('C');
    person = pineapple;
    pineapple->greet();

    getch();
    return 0;   
}



and now? . l implemented the constructors. it still no polymorphism in this case?- thanks for the effort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class Person {
   private:
      string name;   
      int age;
   public:
      Person (string _name, int _age) {
         name = _name;
         age = _age;
      }
      void greet () {
         printf ("\n- Hi my name is '%s'", name);
         printf (" I have '%d' years old", age);
      }
};      

class Teacher: public Person {
   private:
      string course;   
   public:
      Teacher (string _name, int _age, string _course): Person(_name, _age) {
         course = _course;
      }         
      void greet () {      
         Person::greet();      
         printf (" and I'll teach you the course of '%s'.", course );         
      }         
};      

class Student: public Person {
   private:
      char grade;   
   public:
      Student (string _name, int _age, char _grade): Person(_name, _age) {
         grade = _grade;
      }      
      void greet () {      
         Person::greet();      
      printf (" and I come from grade %c.", grade);         
      }         
};      

/* Person
      private: name, age
      public: Person(name, age) {...}
               greet() {...}
   
   Teacher
      private: course
      public: Teacher(name, age, course): Person(name, age)
               greet() {...} // l say: why do I write all again? instead call the Person.greet()
                             // and just add the course; same for Student.
   Student
      private: grade
      public: Student(name, age, grade): Person(name, age)
               greet() {...}
*/

int main () {
   Person unknown ("Unknown",10);
   Teacher jackfruit ("Jack Fruit", 213, "Object oriented programming");
   Student pineapple ("Pineapple", 179 ,'A');

   unknown.greet();
   jackfruit.greet();
   pineapple.greet();   

   getch();
   return 0;  
}


- Hi my name is 'Unknown' I have '10' years old
- Hi my name is 'Jack Fruit' I have '213' years old and I'll teach you the cours
e of 'Object oriented programming'.
- Hi my name is 'Pineapple' I have '179' years old and I come from grade A.
Last edited on
You haven't changed anything.

For comparison:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>
using std::string;

class Person {
   private:
      string name;   
      int age;
   public:
      Person (string _name, int _age)
      : name( _name ), age( _age )
      {}

      void greet () {
         std::cout << "- Hi my name is '" << name << "' I have '" << age << "' years old";
      }
      virtual void blame() { greet(); }
};      

class Teacher: public Person {
   private:
      string course;   
   public:
      Teacher (string _name, int _age, string _course)
      : Person(_name, _age), course( _course )
      {}

      void greet () {      
         Person::greet();      
         std::cout << " and I'll teach you the course of '" << course << "'.";         
      }         
      virtual void blame() { greet(); }
};      

void hello( Person & p ) {
    p.greet();
    std::cout << '\n';
}

void world( Person & p ) {
    p.blame();
    std::cout << '\n';
}

int main () {
   Person unknown("Unknown", 10);
   Teacher jackfruit("Jack Fruit", 213, "Object oriented programming");

   std::cout << "non-virtual:\n";
   hello( unknown );
   hello( jackfruit );

   std::cout << "\nvirtual:\n";
   world( unknown );
   world( jackfruit );
   return 0;  
}

non-virtual:
- Hi my name is 'Unknown' I have '10' years old
- Hi my name is 'Jack Fruit' I have '213' years old

virtual:
- Hi my name is 'Unknown' I have '10' years old
- Hi my name is 'Jack Fruit' I have '213' years old and I'll teach you the course of 'Object oriented programming'.

Look at the functions hello() and world().
They both think that they handle a Person object.
They don't know whether the Person is actually a Person or Student.

The hello() calls non-virtual greet(). The Person::greet(). Every p behaves exactly the same: like a Person.

The world() calls virtual function blame(). What the world() does not know is that if the p is actually a Teacher, then the call to blame() does not resolve to Person::blame(), but to Teacher::blame(). All p's no longer behave the same way. Their behaviour changes depending on the actual type of the referred object.


We want to decouple operations for objects. We want to treat every Person as a Person. If we can do that, then we don't have to change anything if a new Person subclass Programmer pops up. Programmer is a Person too.

What is the point of having Students and Teachers? Lets have just Persons? Oh no, we need variation, exceptions. Polymorphism. Your non-virtual greet() does not allow that.
@keskiverto thanks for the effort. lm really understand every part of your explanation. Getting back to the polymorphism, the idea that I've seen more commonly is to overload methods. like calculateArea() <- Triangle, Rectangle. But Thanks again.
Topic archived. No new replies allowed.