Inheritance and Polymorphism in C++

Inheritance and polymorphism are fundamental concepts in object-oriented programming (OOP) that enable code reusability and modularity. In this article, we will explore these concepts in detail, with examples in C++.

Table of Contents

  1. Introduction to Inheritance
  2. Introduction to Polymorphism
  3. Pure Virtual Functions and Abstract Classes
  4. Function Overriding and Dynamic Binding
  5. Conclusion

1. Introduction to Inheritance

Inheritance allows a new class to inherit the properties and methods of an existing class, enabling code reusability and hierarchy. The new class is called a derived class, and the existing class is called the base class.

1.1. Creating a Derived Class

To create a derived class, use the colon : followed by the access specifier and the name of the base class.

class Base {
public:
void baseFunction() {
// Implementation
}
};

class Derived : public Base {
public:
void derivedFunction() {
// Implementation
}
};

1.2. Access Specifiers

There are three access specifiers in C++: public, protected, and private. They determine the visibility and accessibility of class members.

  • public: Accessible from anywhere.
  • protected: Accessible from the class itself, its derived classes, and friend classes or functions.
  • private: Accessible only from the class itself and friend classes or functions.

2. Introduction to Polymorphism

Polymorphism allows a single interface to represent different types, enabling flexibility and extensibility in code. In C++, polymorphism is achieved through virtual functions and pointers or references to base class objects.

2.1. Virtual Functions

Virtual functions are member functions declared with the virtual keyword in the base class, which can be overridden by derived classes.

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

class Derived : public Base {
public:
void print() override {
cout << "Derived class print" << endl;
}
};

2.2. Polymorphism with Pointers and References

Polymorphism can be achieved using pointers or references to base class objects.

Base* ptr = new Derived(); // Base pointer to a Derived object
ptr->print(); // Output: Derived class print

Base& ref = *ptr; // Base reference to a Derived object
ref.print(); // Output: Derived class print

3. Pure Virtual Functions and Abstract Classes

A pure virtual function is a virtual function with no implementation in the base class. A class containing one or more pure virtual functions is called an abstract class.

3.1. Declaring a Pure Virtual Function

To declare a pure virtual function, use the virtual keyword, followed by the function prototype, and assign it to zero.

class AbstractBase {
public:
virtual void print() = 0; // Pure virtual function
};

3.2. Implementing Pure Virtual Functions in Derived Classes

Derived classes must provide an implementation for each pure virtual function in their base class.

class DerivedFromAbstract : public AbstractBase {
public:
void print() override {
cout << "Implementation of print() in DerivedFromAbstract" << endl;
}
};

3.3. Instantiating Derived Classes

Abstract classes cannot be instantiated, but their derived classes can be.

// AbstractBase abs; // This would cause a compilation error since AbstractBase is an abstract class

DerivedFromAbstract derived; // Instantiating a derived class
derived.print(); // Output: Implementation of print() in DerivedFromAbstract

4. Function Overriding and Dynamic Binding

Function overriding is the process of redefining a base class function in a derived class. Dynamic binding (also known as late binding) is the process of resolving function calls at runtime, based on the type of the object pointed to or referenced.

4.1. Overriding Functions

When a derived class overrides a base class function, it provides a new implementation for the function.

class Base {
public:
virtual void display() {
cout << "Display in Base class" << endl;
}
};

class Derived : public Base {
public:
void display() override {
cout << "Display in Derived class" << endl;
}
};

4.2. Dynamic Binding with Pointers and References

Dynamic binding allows the appropriate function to be called based on the type of the object pointed to or referenced, even when using base class pointers or references.

Base* basePtr = new Base();
Base* derivedPtr = new Derived();

basePtr->display(); // Output: Display in Base class
derivedPtr->display(); // Output: Display in Derived class

delete basePtr;
delete derivedPtr;

5. Conclusion

In this article, we’ve covered the core concepts of inheritance and polymorphism in C++. We have explored how to create derived classes, use access specifiers, and achieve polymorphism with virtual functions and pointers or references to base class objects.

We have also discussed the concepts of pure virtual functions, abstract classes, function overriding, and dynamic binding. Understanding these concepts is essential for writing modular, reusable, and extensible code in C++.