Polymorphism is a fundamental concept in object-oriented programming that allows objects of different classes to be treated as if they were objects of the same class. In C++, polymorphism is achieved through the use of virtual functions, pure virtual functions, function overriding, and function hiding.
1. Virtual functions: A virtual function is a member function of a class that can be overridden by a function of the same name in a derived class. A virtual function is declared using the `virtual` keyword. When a virtual function is called on an object, the appropriate function is resolved at runtime based on the actual type of the object. This allows objects of different classes to be treated as if they were objects of the same class. For example:
class Shape { public: virtual void draw() { cout << "Drawing a shape." << endl; } }; class Circle : public Shape { public: void draw() override { cout << "Drawing a circle." << endl; } }; class Square : public Shape { public: void draw() override { cout << "Drawing a square." << endl; } }; int main() { Shape* shape1 = new Circle(); Shape* shape2 = new Square(); shape1->draw(); // calls Circle::draw() shape2->draw(); // calls Square::draw() delete shape1; delete shape2; return 0; }
In this example, a `Shape` class is defined with a virtual function `draw()`. Two derived classes, `Circle` and `Square`, are defined that override the `draw()` function. In the `main()` function, two `Shape` pointers, `shape1` and `shape2`, are created and assigned to `Circle` and `Square` objects, respectively. When the `draw()` function is called on each object, the appropriate function is resolved at runtime based on the actual type of the object.
2. Pure virtual functions: A pure virtual function is a virtual function that has no implementation in the base class. A class that contains a pure virtual function is called an abstract class, and cannot be instantiated directly. Instead, the class must be subclassed and the pure virtual function must be overridden in the subclass. Pure virtual functions are declared using the `= 0` syntax. For example:
class Shape { public: virtual void draw() = 0; }; class Circle : public Shape { public: void draw() override { cout << "Drawing a circle." << endl; } }; class Square : public Shape { public: void draw() override { cout << "Drawing a square." << endl; } }; int main() { Shape* shape1 = new Circle(); Shape* shape2 = new Square(); shape1->draw(); // calls Circle::draw() shape2->draw(); // calls Square::draw() deleteshape1; delete shape2; return 0; }
In this example, the `Shape` class is defined with a pure virtual function `draw()`. Two derived classes, `Circle` and `Square`, are defined that override the `draw()` function. Because `Shape` contains a pure virtual function, it cannot be instantiated directly. Instead, `Circle` and `Square` are created and assigned to `Shape` pointers, and the `draw()` function is called on each object.
3. Function overriding: Function overriding is the process of providing a new implementation for a virtual function in a derived class. The new implementation replaces the implementation in the base class. A derived class can override a virtual function by providing a function of the same name and signature with the `override` keyword. For example:
class Shape { public: virtual void draw() { cout << "Drawing a shape." << endl; } }; class Circle : public Shape { public: void draw() override { cout << "Drawing a circle." << endl; } }; int main() { Circle c; Shape* s = &c; s->draw(); // calls Circle::draw() return 0; }
In this example, a `Shape` class is defined with a virtual function `draw()`. A `Circle` class is defined that overrides the `draw()` function. In the `main()` function, a `Circle` object is created and assigned to a `Shape` pointer. When the `draw()` function is called on the `Shape` pointer, the appropriate function is resolved at runtime based on the actual type of the object, and the `Circle::draw()` function is called.
4. Function hiding: Function hiding occurs when a derived class defines a function with the same name as a function in the base class, but with a different signature. This can prevent the virtual function in the base class from being overridden in the derived class. For example:
class Shape { public: virtual void draw() { cout << "Drawing a shape." << endl; } }; class Circle : public Shape { public: void draw(int x) { cout << "Drawing a circle at (" << x << ", 0)." << endl; } }; int main() { Circle c; Shape* s = &c; s->draw(); // calls Shape::draw() c.draw(5); // calls Circle::draw(int) return 0; }
In this example, a `Shape` class is defined with a virtual function `draw()`. A `Circle` class is defined that defines a non-virtual function `draw()` with an integer argument. In the `main()` function, a `Circle` object is created and assigned to a `Shape` pointer. When the `draw()` function is called on the `Shape` pointer, the appropriate function is resolved at runtime based on the actual type of the object, and the `Shape::draw()` function is called. When the `draw()` function is called on the `Circle` object directly, the `Circle::draw(int)` function is called, since it has a different signature than the virtual function in the base class.
In summary, polymorphism in C++ allows objects of different classes to be treated as if they were objects of the same class, providing flexibility and modularity in object-oriented programming. Virtual functions, pure virtual functions, function overriding, and function hiding are important concepts for achieving polymorphism in C++.