View RSS Feed

Nandan

Polymorphism in C++

Rating: 2 votes, 2.50 average.
by , 03-26-2013 at 10:08 AM (3219 Views)
One of the important properties of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking benefit of this simple but omnipotent and uncertain feature, that brings Object Oriented Methodologies to its full potential.
Example for simple polymorphism
Code:
#include <iostream>
using namespace std;

class myPolyCls {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
  };

class myobjRectCls: public myPolyCls {
  public:
    int objAre ()
      { return (width * height); }
  };

class myTriCls: public myPolyCls {
  public:
    int objAre ()
      { return (width * height / 2); }
  };

int main () {
  myobjRectCls objRect;
  myTriCls objTri;
  myPolyCls * objPoly1 = &objRect;
  myPolyCls * objPoly2 = &objTri;
  objPoly1->set_values (4,5);
  objPoly2->set_values (4,5);
  cout << objRect.objAre() << endl;
  cout << objTri.objAre() << endl;
  return 0;
}
In function main, we create two pointers that point to objects of class myPolyCls (objPoly1 and objPoly2). Then we assign references to objRect and objTri to these pointers, and because both are objects of classes derived from myPolyCls, both are valid assignment operations.

The only limitation in using *objPoly1 and *objPoly2 instead of objRect and objTri is that both *objPoly1 and *objPoly2 are of type myPolyCls* and therefore we can only use these pointers to refer to the members that myobjRectCls and myTriCls inherit from myPolyCls. For that reason when we call the objAre() members at the end of the program we have had to use diobjRectly the objects objRect and objTri instead of the pointers *objPoly1 and *objPoly2.

In order to use objAre() with the pointers to class myPolyCls, this member should also have been declared in the class myPolyCls, and not only in its derived classes, but the problem is that myobjRectCls and myTriCls implement different versions of objAre, therefore we cannot implement it in the base class. This is when virtual members become handy:

Submit "Polymorphism in C++" to Digg Submit "Polymorphism in C++" to del.icio.us Submit "Polymorphism in C++" to StumbleUpon Submit "Polymorphism in C++" to Google

Tags: 1'", 1axa7a? Add / Edit Tags
Categories
Uncategorized

Comments

  1. Nandan's Avatar
    Virtual members
    A member of a class that can be specified in its derived classes is known as a virtual member.
    If we want to declare a member of a class as virtual, we must predate its declaration with the keyword virtual:
    Here is the simple example for virtual members
    Code:
    #include <iostream>
    using namespace std;
    
    class myPoly {
      protected:
        int width, height;
      public:
        void SetVals (int a, int b)
          { width=a; height=b; }
        virtual int functArea ()
          { return (0); }
      };
    
    class myRect: public myPoly {
      public:
        int functArea ()
          { return (width * height); }
      };
    
    class myTri: public myPoly {
      public:
        int functArea ()
          { return (width * height / 2); }
      };
    
    int main () {
      myRect rect;
      myTri trgl;
      myPoly poly;
      myPoly * objPoly1 = &rect;
      myPoly * objPoly2 = &trgl;
      myPoly * objPoly3 = &poly;
      objPoly1->SetVals (14,15);
      objPoly2->SetVals (14,15);
      objPoly3->SetVals (14,15);
      cout << objPoly1->functArea() << endl;
      cout << objPoly2->functArea() << endl;
      cout << objPoly3->functArea() << endl;
      return 0;
    }
    Now the three classes (myPoly, myRect and myTri) have all the same members: width, height, SetVals() and functArea().

    The member function functArea() has been declared as virtual in the base class because it is later redefined in each derived class. You can verify if you want that if you remove this virtual keyword from the declaration of functArea() within myPoly, and then you run the program the result will be 0 for the three polygons instead of 20, 10 and 0. That is because instead of calling the corresponding functArea() function for each object (myRect::functArea(), myTri::functArea() and myPoly::functArea(), respectively), myPoly::functArea() will be called in all cases since the calls are via a pointer whose type is myPoly*.

    Therefore, what the virtual keyword does is to allow a member of a derived class with the same name as one in the base class to be appropriately called from a pointer, and more precisely when the type of the pointer is a pointer to the base class but is pointing to an object of the derived class, as in the above example.

    A class that declares or inherits a virtual function is called a polymorphic class.

    Note that despite of its virtuality, we have also been able to declare an object of type myPoly and to call its own functArea() function, which always returns 0.
  2. Nandan's Avatar
    Abstract base classes

    Abstract base classes are something very similar to our myPolyClas class of our past example. The only difference is that in our past example we have defined a valid myArea() function with a minimal functionality for objects that were of class myPolyClas (like the object poly), whereas in an abstract base classes we could leave that myArea() member function without implementation at all. This is done by appending =0 (equal to zero) to the function declaration.

    An abstract base myPolyClas class is shown below:
    Code:
    // abstract class myPolyClas
    class myPolyClas {
      protected:
        int iWid, iHei;
      public:
        void ValsSet (int a, int b)
          { iWid=a; iHei=b; }
        virtual int myArea () =0;
    };
    Notice how we appended =0 to virtual int myArea () instead of specifying an implementation for the function. This type of function is called a pure virtual function, and all classes that contain at least one pure virtual function are abstract base classes.

    The main difference between an abstract base class and a regular polymorphic class is that because in abstract base classes at least one of its members lacks implementation we cannot create instances (objects) of it.

    But a class that cannot instantiate objects is not totally useless. We can create pointers to it and take advantage of all its polymorphic abilities. Therefore a declaration like:
    Code:
    myPolyClas poly;
    would not be valid for the abstract base class we have just declared, because tries to instantiate an object. Nevertheless, the following pointers:
    Code:
    myPolyClas * obj2Poly1;
    myPolyClas * obj2Poly2;
    This would be absolutely valid.

    This is so for as long as myPolyClas includes a pure virtual function and therefore it's an abstract base class. However, pointers to this abstract base class can be used to point to objects of derived classes.

    Here you have the complete example for abstract base class:
    Code:
    #include <iostream>
    using namespace std;
    
    class myPolyClas {
      protected:
        int iWid, iHei;
      public:
        void ValsSet (int a, int b)
          { iWid=a; iHei=b; }
        virtual int myArea (void) =0;
      };
    
    class myRect: public myPolyClas {
      public:
        int myArea (void)
          { return (iWid * iHei); }
      };
    
    class myTri: public myPolyClas {
      public:
        int myArea (void)
          { return (iWid * iHei / 2); }
      };
    
    int main () {
      myRect rect;
      myTri trgl;
      myPolyClas * obj2Poly1 = &rect;
      myPolyClas * obj2Poly2 = &trgl;
      obj2Poly1->ValsSet (4,5);
      obj2Poly2->ValsSet (4,5);
      cout << obj2Poly1->myArea() << endl;
      cout << obj2Poly2->myArea() << endl;
      return 0;
    }
    If you review the program you will notice that we refer to objects of different but related classes using a unique type of pointer (myPolyClas*). This can be tremendously useful. For example, now we can create a function member of the abstract base class myPolyClas that is able to print on screen the result of the myArea() function even though myPolyClas itself has no implementation for this function:
    Code:
    #include <iostream>
    using namespace std;
    
    class myPolyClas {
      protected:
        int iWid, iHei;
      public:
        void ValsSet (int a, int b)
          { iWid=a; iHei=b; }
        virtual int myArea (void) =0;
        void printmyArea (void)
          { cout << this->myArea() << endl; }
      };
    
    class myRect: public myPolyClas {
      public:
        int myArea (void)
          { return (iWid * iHei); }
      };
    
    class myTri: public myPolyClas {
      public:
        int myArea (void)
          { return (iWid * iHei / 2); }
      };
    
    int main () {
      myRect rect;
      myTri trgl;
      myPolyClas * obj2Poly1 = &rect;
      myPolyClas * obj2Poly2 = &trgl;
      obj2Poly1->ValsSet (4,5);
      obj2Poly2->ValsSet (4,5);
      obj2Poly1->printmyArea();
      obj2Poly2->printmyArea();
      return 0;
    }
    Virtual members and abstract classes grant C++ the polymorphic characteristics that make object-oriented programming such a useful instrument in big projects. Of course, we have seen very simple uses of these features, but these features can be applied to arrays of objects or dynamically allocated objects.

    Let's end with the same example again, but this time with objects that are dynamically allocated:
    Example for dynamic allocation and polymorphism
    Code:
    #include <iostream>
    using namespace std;
    
    class myPolyClas {
      protected:
        int iWid, iHei;
      public:
        void ValsSet (int a, int b)
          { iWid=a; iHei=b; }
        virtual int myArea (void) =0;
        void printmyArea (void)
          { cout << this->myArea() << endl; }
      };
    
    class myRect: public myPolyClas {
      public:
        int myArea (void)
          { return (iWid * iHei); }
      };
    
    class myTri: public myPolyClas {
      public:
        int myArea (void)
          { return (iWid * iHei / 2); }
      };
    
    int main () {
      myPolyClas * obj2Poly1 = new myRect;
      myPolyClas * obj2Poly2 = new myTri;
      obj2Poly1->ValsSet (14,15);
      obj2Poly2->ValsSet (14,15);
      obj2Poly1->printmyArea();
      obj2Poly2->printmyArea();
      delete obj2Poly1;
      delete obj2Poly2;
      return 0;
    }
    Notice that the obj2Poly pointers:
    Code:
    myPolyClas * obj2Poly1 = new myRect;myPolyClas * obj2Poly2 = new myTri;
    Tease are declared being of type pointer to myPolyClas but the objects dynamically allocated have been declared having the derived class type directly.