0% found this document useful (0 votes)
65 views

OOP Unit 3 Notes

sppu eng

Uploaded by

jayesh bachhav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views

OOP Unit 3 Notes

sppu eng

Uploaded by

jayesh bachhav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

1|Page

Unit – III
Polymorphism
1. Polymorphism

1.1 Introduction to Polymorphism

The word “polymorphism” means having many forms. In simple words, we can define
polymorphism as the ability of a message to be displayed in more than one form. A real-life
example of polymorphism is a person who at the same time can have different characteristics.
A man at the same time is a father, a husband, and an employee. So, the same person exhibits
different behavior in different situations. This is called polymorphism. Polymorphism is
considered one of the important features of Object-Oriented Programming.

1.2 Types of Polymorphism

There are two types of polymorphism: Compile-Time Polymorphism and Runtime


Polymorphism

1.3 Concept of Overloading

C++ allows you to specify more than one definition for a function name or an operator in the
same scope, which is called function overloading and operator overloading respectively.

An overloaded declaration is a declaration that is declared with the same name as a previously
declared declaration in the same scope, except that both declarations have different arguments
and obviously different definition (implementation).
2|Page

When you call an overloaded function or operator, the compiler determines the most
appropriate definition to use, by comparing the argument types you have used to call the
function or operator with the parameter types specified in the definitions. The process of
selecting the most appropriate overloaded function or operator is called overload resolution.

1.4 Operator Overloading

Operator overloading in C++ allows you to redefine how operators work for user-defined
types, such as classes and structures. By overloading operators, you can provide custom
implementations for operations such as addition, subtraction, comparison, etc., on objects of a
class, much like how they work for built-in types like integers or floating-point numbers.

Rules to be followed when overloading an operator:

 Only existing operators can be overloaded — No new operators can be created.


 At least one operand must be a user-defined type (class or struct).
 Operator precedence and associativity cannot be changed — The overloaded
operator follows the original rules.
 Cannot change the number of operands — Unary operators remain unary, and binary
operators remain binary.
 Some operators must be overloaded as member functions, like =, [], ->, and ().
 Binary operators can be overloaded as either member or friend functions for
greater flexibility.
 Overloaded operators should have intuitive and expected behavior, similar to their
usual functionality.
 Operators like ++ and -- can have both prefix and postfix versions, with different
syntax.
 The return type must be appropriate for the operation (e.g., returning an object or a
reference).
 Operators that cannot be overloaded include ::, ., .*, ?:, and sizeof.

Syntax of Operator Overloading

To overload an operator, you define a function where the keyword operator is followed by
the symbol of the operator you wish to overload. The function must be a member function of a
class or a friend function, depending on the context.
3|Page

Example: Program to Overload - Operator for Subtracting Complex Numbers:

#include <iostream>
using namespace std;

class Complex {
private:
int real, imag; // Private members for real and imaginary parts

public:
// Constructor to initialize complex numbers
Complex(int r = 0, int i = 0) : real(r), imag(i) {}

// Member function to overload the '-' operator


Complex operator - (const Complex& other) {
Complex result;
result.real = real - other.real;
result.imag = imag - other.imag;
return result;
}

// Function to display a complex number


void display() const {
cout << real << " + " << imag << "i" << endl;
}
};

int main() {
Complex c1(10, 5); // First complex number
Complex c2(4, 2); // Second complex number

Complex c3 = c1 - c2; // Calls the overloaded '-' operator to


subtract c2 from c1
4|Page

cout << "Result of c1 - c2: ";


c3.display(); // Output: 6 + 3i

return 0;
}
1.5 Overloading Unary Operators

Overloading of unary operators in C++ allows you to define custom behavior for unary
operators when they are applied to objects of a class. Unary operators operate on a single
operand and include operators such as - (negation), ++ (increment), -- (decrement), ! (logical
NOT), and ~ (bitwise NOT).

Key Points of Unary Operator Overloading:

 Unary operators take a single operand.

 They can be overloaded as member functions or friend functions.

 When overloaded as member functions, they don't require parameters since the operand
is the object itself (*this).

 When overloaded as non-member functions (friend functions), they require one


argument.

Syntax:

ReturnType operator OperatorSymbol();

Example 1: Unary -- Operator Overloading Using a Member Function

#include <iostream>
using namespace std;

class Counter {
private:
int value;

public:
5|Page

// Constructor to initialize the counter


Counter(int v = 0) : value(v) {}

// Overloading unary '--' operator as a member function (prefix


decrement)
Counter operator -- () {
--value; // Decrement the value
return *this;
}

// Display function to show the current value


void display() const {
cout << "Value: " << value << endl;
}
};

int main() {
Counter count1(10);

// Using overloaded '--' operator (member function)


cout << "Using overloaded '--' operator (Member function):" <<
endl;
--count1; // Calls the overloaded '--' operator
count1.display(); // Output: Value: 9

return 0;
}
Output:
Using overloaded '--' operator (Member function):
Value: 9

Example 2: Unary ++ Operator Overloading Using a Friend Function

#include <iostream>
6|Page

using namespace std;

class Counter {
private:
int value;

public:
// Constructor to initialize the counter
Counter(int v = 0) : value(v) {}

// Declaring friend function to overload '++' operator


friend Counter operator ++ (Counter& obj);

// Display function to show the current value


void display() const {
cout << "Value: " << value << endl;
}
};

// Definition of friend function to overload the '++' operator


Counter operator ++ (Counter& obj) {
++obj.value; // Increment the value of the object
return obj;
}

int main() {
Counter count2(20);

// Using overloaded '++' operator (friend function)


cout << "Using overloaded '++' operator (Friend function):" <<
endl;
++count2; // Calls the overloaded '++' operator
7|Page

count2.display(); // Output: Value: 21

return 0;
}
Output:

Using overloaded '++' operator (Friend function):

Value: 21

1.6 Overloading Binary Operators

Binary operators are those that operate on two operands, such as +, -, *, /, ==, and !=. When
overloading a binary operator in C++, you define how the operator should behave when used
between two objects of a class (or between an object and a built-in type, in some cases).

 Binary operators are typically overloaded as either a member function or a friend


function.

 The operator must take one argument if it is a member function (the other operand is
implicitly the object invoking the operator).

 If it’s a friend function, it takes two arguments (both operands).

Syntax:

ReturnType operator OperatorSymbol(const Type& other) {


// Function body
}
Example 1: Using binary overloaded operator (= =) to compare two strings

#include <iostream>
#include <cstring> // For strcmp function
using namespace std;

class String {
private:
char* str; // Pointer to dynamically store the string
8|Page

public:
// Constructor to initialize string
String(const char* s = "") {
str = new char[strlen(s) + 1]; // Allocate memory
strcpy(str, s); // Copy the input string
}

// Destructor to deallocate memory


~String() {
delete[] str;
}

// Overloading the '==' operator to compare two strings


bool operator == (const String& other) const {
return strcmp(str, other.str) == 0; // Compare strings using
strcmp
}

// Display the string


void display() const {
cout << str << endl;
}
};

int main() {
String s1("Hello");
String s2("Hello");
String s3("World");

// Comparing two strings using the overloaded '==' operator


if (s1 == s2) {
9|Page

cout << "s1 and s2 are equal." << endl; // Output: s1 and s2
are equal.
} else {
cout << "s1 and s2 are not equal." << endl;
}

if (s1 == s3) {
cout << "s1 and s3 are equal." << endl;
} else {
cout << "s1 and s3 are not equal." << endl; // Output: s1
and s3 are not equal.
}

return 0;
}
Example 2: Program to overload insertion (<<) and extraction (>>) operator:

#include <iostream>
using namespace std;

class Complex
{
private:
int real, imag;
public:
Complex(int r = 0, int i =0)
{ real = r; imag = i; }
friend ostream & operator << (ostream &out, const Complex &c);
friend istream & operator >> (istream &in, Complex &c);
};

ostream & operator << (ostream &out, const Complex &c){


out << c.real << "+";
10 | P a g e

out << c.imag << "i" << endl;


return out;
}

istream & operator >> (istream &in, Complex &c){


cout << "Enter Real Part ";
in >> c.real;
cout << "Enter Imaginary Part ";
in >> c.imag;
return in;
}

int main(){
Complex c1;
cin >> c1;
cout << "The complex number is ";
cout << c1;
return 0;
}
1.7 Data Conversion - Type Casting (implicit and explicit)

Type casting in C++ refers to the process of converting one data type to another. This
conversion can be done implicitly (automatically) by the compiler or explicitly (manually) by
the programmer. Type casting is important to ensure that the right data type is being used for
operations, especially in expressions involving mixed data types.

Types of Type Casting

1. Implicit Type Casting (Automatic Conversion)

2. Explicit Type Casting (Manual Conversion)

1. Implicit Type Casting

Definition: Implicit type casting, also known as automatic type conversion, occurs when the
compiler automatically converts one data type to another without explicit instructions from the
11 | P a g e

programmer. This usually happens in expressions where different data types are involved, and
the compiler promotes the smaller or less precise type to a larger or more precise type to avoid
data loss.

Examples:

 Numeric Promotion: When an integer is used in a floating-point operation, the integer


is automatically converted to a float.

int intVal = 10;


float floatVal = 5.5;
float result = intVal + floatVal; // intVal is implicitly
converted to float
cout << result; // Output: 15.5

 Character to Integer: When a character is assigned to an integer variable, its ASCII


value is used.

char ch = 'A'; // ASCII value of 'A' is 65


int asciiValue = ch; // Implicit conversion from char to int
cout << asciiValue; // Output: 65

2. Explicit Type Casting

Definition: Explicit type casting, also known as type casting or manual conversion, occurs
when the programmer explicitly specifies the type to which a value should be converted. This
is often necessary when converting from a larger data type to a smaller data type, as it may lead
to data loss.

C++ provides four types of casts:

 static_cast: Used for safe conversions between types.

 dynamic_cast: Used for safely downcasting in class hierarchies (polymorphism).

 const_cast: Used to add or remove the const qualifier.

 reinterpret_cast: Used for low-level casting, often between incompatible types.

Syntax:

new_type variable = static_cast<new_type>(expression);


12 | P a g e

Example:

double doubleVal = 10.75;


int intVal = static_cast<int>(doubleVal); // Explicitly casting double
to int
cout << intVal; // Output: 10

1.8 Pitfalls of Operator Overloading and Conversion

1.8.1 Operator Overloading

Ambiguity: Overloaded operators may lead to confusion if their behavior is not intuitive or
clear to users.

Performance Issues: Complex overloaded operators can introduce overhead, affecting the
performance of time-critical applications.

Inconsistent Behavior: Overloaded operators may not behave consistently with built-in types,
leading to unexpected results.

Unintended Side Effects: Operators may modify object states, leading to unintended
consequences if not carefully implemented.

Reduced Readability: Code can become less readable if overloaded operators are not familiar
or clear, making it harder for other developers to understand.

1.8.2 Data Conversion

Implicit Conversions: Unintended implicit conversions can lead to unexpected behavior or


hard-to-debug issues.

Loss of Information: Converting from a larger to a smaller type can result in data loss or
precision issues.

Unexpected Behavior: Overloaded conversion operators can cause unpredictable behavior,


especially with implicit conversions.

Performance Overhead: Implicit conversions may introduce unnecessary overhead,


particularly in performance-critical sections of code.

Reduced Type Safety: Overusing implicit conversions can lower type safety, making it
difficult to track variable types and their usage.
13 | P a g e

1.9 Keywords explicit and mutable

In C++, keywords serve different purposes, primarily related to data members of classes and
constructors, respectively.

1.9.1 mutable Keyword

Purpose: The mutable keyword allows a member variable of a class to be modified even if
the containing object is declared as const. This is useful for situations where you want to keep
some internal state mutable without affecting the overall immutability of the object.

Usage: You typically declare a data member as mutable when you need to change its value
within a const member function.

Example:

#include <iostream>
using namespace std;
class MyClass {
private:
mutable int counter; // mutable member
public:
MyClass() : counter(0) {}

void increment() const {


// This function is const, but we can modify the mutable
member.
counter++;
}

int getCounter() const {


return counter;
}
};
int main() {
const MyClass obj;
14 | P a g e

obj.increment(); // Allowed because counter is mutable


cout << "Counter: " << obj.getCounter() << endl; // Output:
Counter: 1
return 0;
}
1.9.2. explicit Keyword

Purpose: The explicit keyword is used in constructors to prevent implicit conversions and
copy-initialization. When a constructor is marked as explicit, it cannot be used for implicit
type conversions, which helps to avoid unintentional conversions that can lead to errors.

Usage: You typically use explicit when defining constructors that take a single argument or
when defining conversion operators.

Example:

#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
// Constructor marked as explicit
explicit MyClass(int v) : value(v) {}

int getValue() const {


return value;
}
};

int main() {
MyClass obj1(5); // OK: Direct initialization
cout << "Value: " << obj1.getValue() << endl; // Output: Value: 5
15 | P a g e

// MyClass obj2 = 10; // Error: Cannot implicitly convert int to


MyClass (uncommenting this line would cause a compilation error)

MyClass obj3 = MyClass(10); // OK: Explicit conversion using


constructor
cout << "Value: " << obj3.getValue() << endl; // Output: Value:
10

return 0;
}
1.10 Function Overloading

Function Overloading in C++ allows you to define multiple functions with the same name
but different parameters (i.e., different types or numbers of parameters). This feature enables
the same function name to be used for different types of operations, enhancing code readability
and usability.

Key Points about Function Overloading

 Same Name: All overloaded functions must have the same name.

 Different Parameters: They must differ in the type or number of their parameters
(called the function signature).

 Return Type: The return type is not considered part of the function signature, so it
cannot be used to distinguish between overloaded functions.

Example:

#include <iostream>
using namespace std;
// Function to add two integers
int add(int a, int b) {
return a + b;
}

// Function to add two floats


float add(float a, float b) {
16 | P a g e

return a + b;
}

// Function to add two doubles


double add(double a, double b) {
return a + b;
}

int main() {
// Testing overloaded functions
int intResult = add(5, 10); // Calls the int version
float floatResult = add(5.5f, 3.2f); // Calls the float version
double doubleResult = add(5.5, 3.3); // Calls the double version

// Output the results


cout << "Integer Addition: " << intResult << endl; // Output: 15
cout << "Float Addition: " << floatResult << endl; // Output: 8.7
cout << "Double Addition: " << doubleResult << endl; // Output:
8.8

return 0;
}

2. Run-Time Polymorphism
Run-time polymorphism, also known as dynamic polymorphism, is a feature in C++ that
allows a program to determine which function to call at runtime based on the type of the object
being referred to, rather than the type of the pointer or reference. This is typically achieved
through the use of virtual functions and inheritance.

2.1 Pointers to Base Class

In C++, pointers to base classes are used to refer to objects of derived classes through a base
class pointer. This concept is fundamental in achieving polymorphism, allowing a single
interface to represent different underlying data types.
17 | P a g e

Key Concepts

1. Base Class and Derived Class:

o A base class is a general class that can be extended to create derived classes,
which inherit its properties and behaviors.

o Derived classes can override or extend the functionality of the base class.

2. Pointer to Base Class:

o A pointer of the base class type can hold the address of an object of a derived
class. This enables the base class pointer to invoke overridden functions in the
derived class, achieving run-time polymorphism.

3. Virtual Functions:

o When a base class function is declared as virtual, the appropriate derived class
function is called based on the actual object type that the base class pointer is
pointing to, not the type of the pointer itself.

Example:

#include <iostream>
using namespace std;

// Base class
class Shape {
public:
virtual void draw() { // Virtual function
cout << "Drawing Shape" << endl;
}
};

// Derived class
class Circle : public Shape {
public:
void draw() override { // Override base class function
18 | P a g e

cout << "Drawing Circle" << endl;


}
};

// Another derived class


class Square : public Shape {
public:
void draw() override { // Override base class function
cout << "Drawing Square" << endl;
}
};

int main() {
Shape* shapePtr; // Base class pointer

Circle circle; // Derived class object


Square square; // Another derived class object

// Pointing to derived class object


shapePtr = &circle;
shapePtr->draw(); // Output: Drawing Circle

// Pointing to another derived class object


shapePtr = &square;
shapePtr->draw(); // Output: Drawing Square

return 0;
}
2.2 Virtual Base Class

A virtual base class in C++ is used in cases of multiple inheritance to prevent the duplication
of base class members. When a class is inherited by more than one derived class, and both
19 | P a g e

derived classes are inherited by another class (diamond problem), using a virtual base class
ensures that only one instance of the base class is created and shared by all derived classes.

Diamond Problem in Multiple Inheritance

Consider this situation:

 Class A is a base class.

 Class B and Class C are derived from Class A.

 Class D is derived from both Class B and Class C.

If Class A contains some members, Class D will inherit Class A's members twice (once via
Class B and once via Class C), leading to ambiguity and duplication. This is known as the
diamond problem in multiple inheritance.

Solution: Virtual Base Class

By declaring Class A as a virtual base class when inherited by Class B and Class C, only one
instance of Class A will be created and shared among the derived classes, resolving the
ambiguity.

Example of Virtual Base Class

#include <iostream>
using namespace std;

// Base class
class A {
public:
int value;
A() {
value = 10;
cout << "Constructor of A called" << endl;
}
};

// Derived classes with virtual inheritance


20 | P a g e

class B : virtual public A {


public:
B() {
cout << "Constructor of B called" << endl;
}
};

class C : virtual public A {


public:
C() {
cout << "Constructor of C called" << endl;
}
};

// Final derived class


class D : public B, public C {
public:
D() {
cout << "Constructor of D called" << endl;
}
};

int main() {
D obj;
cout << "Value from class A: " << obj.value << endl; // No
ambiguity
return 0;
}
2.3 Virtual Function and its Significance in C++

A virtual function in C++ is a member function that is declared within a base class and is
intended to be overridden in derived classes. When a function is marked as virtual in a base
class, C++ enables run-time polymorphism, which allows the program to determine which
21 | P a g e

function to invoke (the base class or the derived class version) at runtime, based on the actual
object type that the pointer or reference is pointing to.

Syntax of a Virtual Function

The virtual keyword is used in the base class to indicate that the function can be overridden in
derived classes:

class Base {
public:
virtual void show() {
cout << "Base class show function" << endl;
}
};
Key Characteristics of Virtual Functions:

1. Dynamic Binding:

o Normally, C++ uses static binding (compile-time), where the function to be


called is determined by the type of the pointer or reference. However, for virtual
functions, C++ uses dynamic binding (run-time) to determine the actual object
type and calls the appropriate function.

2. Overriding in Derived Classes:

o A derived class can override the virtual function of a base class, providing its
own specific implementation.

3. Base Class Pointers/References:

o Virtual functions are primarily useful when a base class pointer or reference is
used to point to a derived class object.

4. Virtual Table (V-Table):

o The compiler creates a virtual table (v-table) for each class with virtual
functions. This table holds pointers to the actual functions that should be called
for each object.

5. Use of override and final:


22 | P a g e

o In modern C++, the override keyword is used in the derived class to explicitly
state that the function is intended to override a virtual function.

o The final specifier can be used to prevent further overriding of a virtual


function in subsequent derived classes.

2.4 Pure Virtual Function and Virtual Table

2.4.1 Pure Virtual Func on

A pure virtual function in C++ is a virtual function that has no implementation in the base
class and is declared using the = 0 syntax. This concept is fundamental in defining abstract
classes. An abstract class cannot be instantiated directly and serves as a blueprint for derived
classes, which must provide concrete implementations of the pure virtual functions.

Key Points:

1. Syntax: A pure virtual function is declared in the base class as follows:

class AbstractClass {
public:
virtual void pureVirtualFunction() = 0; // Pure virtual function
};
2. Abstract Class: A class containing at least one pure virtual function is called an abstract
class. This class cannot be instantiated, meaning you cannot create objects of the abstract class
directly.

3. Implementation Requirement: Derived classes must override all pure virtual functions to
become concrete classes that can be instantiated.

4. Enforcing Interface: Pure virtual functions enforce that certain functions must be
implemented in derived classes, thus providing a common interface while allowing flexibility
in the implementation.

2.4.2 Virtual Table (V-Table)

A virtual table (or v-table) is a mechanism used by C++ to support dynamic (run-time)
polymorphism through virtual functions. It is an internal structure that stores pointers to the
virtual functions of a class, allowing the correct function to be called at runtime based on the
actual object type.
23 | P a g e

Key Points:

1. Structure: Each class that has virtual functions has its own v-table. The v-table contains
pointers to the virtual functions that are defined in that class.

2. Object Representation: Each object of a class with virtual functions typically contains a
pointer (often called the vptr) to its class's v-table. This pointer allows the program to access
the correct function implementations at runtime.

3. Dynamic Dispatch: When a virtual function is called through a base class pointer, the
program uses the vptr of the actual object to look up the appropriate function address in the
v-table and execute that function. This process is known as dynamic dispatch.

4. Overriding Functions: If a derived class overrides a virtual function, the v-table for that
derived class will point to the overridden function instead of the base class function.

Example of Virtual Table Concept:

#include <iostream>
using namespace std;

class Base {
public:
virtual void func() {
cout << "Base function" << endl;
}
};

class Derived : public Base {


public:
void func() override {
cout << "Derived function" << endl;
}
};

int main() {
24 | P a g e

Base* b; // Base class pointer


Derived d; // Derived class object
b = &d; // Base pointer points to derived object

b->func(); // Calls Derived::func() due to v-table


return 0;
}
2.5 Virtual Destructor

A virtual destructor in C++ is a destructor declared with the virtual keyword in a base class.
It ensures that the correct destructor is called for derived class objects when they are deleted
through a base class pointer. This is crucial for proper resource management and memory
cleanup, especially in inheritance hierarchies.

Key Points About Virtual Destructors

1. Purpose: Virtual destructors prevent resource leaks by ensuring that when an object of a
derived class is deleted through a base class pointer, the destructor for the derived class is
executed before the base class destructor.

2. Declaration: A virtual destructor is declared in the base class like any other virtual function:

class Base {
public:
virtual ~Base() {
// Cleanup code for Base class
}
};
3. Behavior: When a derived class overrides a destructor, if the base class destructor is virtual,
it guarantees that the derived class destructor will be invoked first, followed by the base class
destructor.

4. Memory Management: Using a virtual destructor is essential when working with dynamic
memory allocation and polymorphism to ensure that all allocated resources are properly
released.
25 | P a g e

5. Destructor Chaining: The virtual destructor mechanism ensures that destructors are called
in the correct order (derived class first, then base class) during object destruction.

Example:
#include <iostream>
using namespace std;

// Base class
class Base {
public:
// Virtual destructor
virtual ~Base() {
cout << "Base destructor called" << endl;
}
};

// Derived class
class Derived : public Base {
public:
~Derived() override {
cout << "Derived destructor called" << endl;
}
};

int main() {
Base* b = new Derived(); // Base pointer to Derived object
delete b; // Correctly calls Derived destructor, then Base
destructor

return 0;
}
2.6 Abstract Base Class
26 | P a g e

An abstract class in C++ is a class that cannot be instantiated (i.e., you cannot create objects
of an abstract class). It is primarily used as a base class for other classes to inherit from. An
abstract class is declared when it contains at least one pure virtual function.

A pure virtual function is a virtual function that has no definition in the base class. It is meant
to be overridden by derived classes, and its syntax is defined using = 0 at the end of the function
declaration.

Syntax of Abstract Class:

class AbstractClass {
public:
virtual void pureVirtualFunction() = 0; // Pure virtual function
};
Example:

Suppose you are creating a program to model different types of employees in a company. The
base class Employee could be an abstract class because every employee should have a function
to calculate their salary, but the specific implementation of that function will differ for different
types of employees like Manager, Engineer, etc.

#include <iostream>
using namespace std;

// Abstract base class


class Employee {
public:
virtual void calculateSalary() = 0; // Pure virtual function
};

// Derived class
class Manager : public Employee {
public:
void calculateSalary() override {
cout << "Calculating salary for Manager." << endl;
27 | P a g e

}
};

// Derived class
class Engineer : public Employee {
public:
void calculateSalary() override {
cout << "Calculating salary for Engineer." << endl;
}
};

int main() {
// Employee emp; // Error: Cannot instantiate an abstract class

Manager m;
Engineer e;

m.calculateSalary(); // Calls Manager's implementation


e.calculateSalary(); // Calls Engineer's implementation

return 0;
}

2.7 Difference between Compile Time Polymorphism and Run Time


Polymorphism

Compile Time Polymorphism Run Time Polymorphism


In Compile time Polymorphism, the call is In Run time Polymorphism, the call is not
resolved by the compiler. resolved by the compiler.
It is also known as Static binding, Early It is also known as Dynamic binding, Late
binding and overloading as well. binding and overriding as well.
It is achieved by method overloading. It is achieved by virtual functions and
pointers.
28 | P a g e

It provides fast execution because the It provides slow execution as compare to


method that needs to be executed is known early binding because the method that needs
early at the compile time. to be executed is known at the runtime.
Compile time polymorphism is less flexible Run time polymorphism is more flexible as
as all things execute at compile time. all things execute at run time.
Inheritance is not involved. Inheritance is involved.

You might also like