Cpp Programming Function Overriding And Virtual Functions Complete Guide
Understanding the Core Concepts of CPP Programming Function Overriding and Virtual Functions
C++ Programming: Function Overriding and Virtual Functions
Introduction: In C++, function overriding and virtual functions are key concepts in object-oriented programming that enable polymorphism, allowing a derived class to provide a specific implementation of a function that is already defined in its base class. Understanding how these features work is crucial for developing robust and scalable applications.
Function Overriding: Function overriding occurs when a derived class provides a specific implementation of a function that is already defined in its base class. This is a form of run-time polymorphism where the function to be executed is determined at runtime.
Key Points for Function Overriding:
- Same Signature: The function in the derived class must have the same signature (same return type, same name, and same parameters) as a virtual function in the base class.
- Access Specifiers: The access specifier of the function in the derived class can be more permissive, but not less (e.g., if the function is protected in the base class, it can be public in the derived class, but not the other way around).
- Static vs. Non-static Functions: A static function in a base class cannot be overridden by a function in the derived class with the same name. Overriding requires polymorphism, which is supported by non-static functions.
- Usage: Overriding is used when a derived class needs to provide a specific functionality that is different from the base class implementation.
class Base {
public:
void display() {
cout << "Display from Base Class" << endl;
}
};
class Derived : public Base {
public:
void display() {
cout << "Display from Derived Class" << endl;
}
};
int main() {
Base *basePointer;
Derived derivedObject;
basePointer = &derivedObject;
basePointer->display(); // Output: Display from Base Class
return 0;
}
In the above example, the display
function in the Derived
class overrides the display
function in the Base
class. However, since the display
function is not virtual, the output is from the Base
class.
Virtual Functions:
To enable overriding with run-time polymorphism, the base class function needs to be declared as virtual
. This informs the compiler that the function might be overridden in derived classes, enabling dynamic dispatch.
Key Points for Virtual Functions:
- Declaration: A virtual function is declared by preceding the function declaration in the base class with the keyword
virtual
. - Pure Virtual Functions: A virtual function can be declared as pure virtual by initializing it to 0. This makes the class abstract, meaning it cannot be instantiated directly and must be inherited for use.
- Dynamic Dispatch: When a derived class overrides a virtual function, the function to be executed is determined at runtime based on the object's actual type, not the type of the pointer or reference used to invoke the function.
- Benefits: Virtual functions allow for a flexible and extensible design. They enable the use of interfaces and polymorphism, which are powerful features in C++.
class Base {
public:
virtual void display() {
cout << "Display from Base Class" << endl;
}
};
class Derived : public Base {
public:
void display() {
cout << "Display from Derived Class" << endl;
}
};
int main() {
Base *basePointer;
Derived derivedObject;
basePointer = &derivedObject;
basePointer->display(); // Output: Display from Derived Class
return 0;
}
In this example, the display
function is virtual in the Base
class. When basePointer->display()
is called, it executes the display
function in the Derived
class due to dynamic dispatch.
Pure Virtual Functions: Pure virtual functions are used in abstract classes to define interfaces. A class containing at least one pure virtual function cannot be instantiated directly.
Key Points for Pure Virtual Functions:
- Syntax: A pure virtual function is declared by initializing it to 0 (
virtual void functionName() = 0;
). - Abstract Classes: An abstract class is a class that cannot be instantiated and must be inherited. It can have pure virtual functions.
- Implementation: Derived classes must provide an implementation for all pure virtual functions to become concrete (non-abstract).
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
class Circle : public Shape {
public:
void draw() {
cout << "Drawing a circle" << endl;
}
};
int main() {
Shape *shapePointer;
Circle circleObject;
shapePointer = &circleObject;
shapePointer->draw(); // Output: Drawing a circle
return 0;
}
In this example, Shape
is an abstract class due to the pure virtual function draw
. It must be overridden by derived classes like Circle
for them to be instantiated.
Conclusion: Understanding function overriding and virtual functions is essential for mastering C++ and writing efficient, reusable, and maintainable code. These features enable polymorphism, providing a powerful mechanism for implementing dynamic behavior and adhering to the principles of object-oriented design.
Important Keywords:
- Function Overriding
- Virtual Functions
- Polymorphism
- Run-time Polymorphism
- Base Class
- Derived Class
- Dynamic Dispatch
- Pure Virtual Functions
- Abstract Classes
- Interface
- Method Signature
- Inheritance
- OOP (Object-Oriented Programming)
Online Code run
Step-by-Step Guide: How to Implement CPP Programming Function Overriding and Virtual Functions
Understanding Function Overriding and Virtual Functions
Function Overriding: When a subclass (derived class) has a definition for one of the member functions of the base class, that function is said to be overridden.
Virtual Function: A virtual function is a member function in a base class that is declared using the
virtual
keyword. When you use a virtual function, you can call the function of the derived class through a base class pointer or a base class reference. This is a key part of polymorphism in C++.
Step-by-Step Examples
Step 1: Simple Function Overriding
First, let's see a simple example of function overriding without virtual functions.
#include <iostream>
class Base {
public:
void display() {
std::cout << "Display function of Base class" << std::endl;
}
};
class Derived : public Base {
public:
void display() {
std::cout << "Display function of Derived class" << std::endl;
}
};
int main() {
Base* basePtr;
Derived derivedObj;
basePtr = &derivedObj;
basePtr->display(); // This will call Base class function display
return 0;
}
Output:
Display function of Base class
Explanation:
In this example, the function display()
is overridden in the Derived
class. However, when we call display()
through a base class pointer, it calls the base class's function because the function is not declared as virtual in the base class.
Step 2: Adding Virtual Function
Now, let's modify the code to use a virtual function.
#include <iostream>
class Base {
public:
virtual void display() {
std::cout << "Display function of Base class" << std::endl;
}
};
class Derived : public Base {
public:
void display() override { // Override keyword is optional but recommended
std::cout << "Display function of Derived class" << std::endl;
}
};
int main() {
Base* basePtr;
Derived derivedObj;
basePtr = &derivedObj;
basePtr->display(); // This will call Derived class function display
return 0;
}
Output:
Display function of Derived class
Explanation:
By declaring display()
as a virtual function in the base class, the derived class's function display()
gets called when invoked through a base class pointer, demonstrating polymorphism.
Step 3: Virtual Destructors
Virtual destructors are important to ensure proper cleanup of derived class objects when accessed through base class pointers.
#include <iostream>
class Base {
public:
Base() {
std::cout << "Constructor of Base class" << std::endl;
}
virtual ~Base() {
std::cout << "Destructor of Base class" << std::endl;
}
virtual void display() {
std::cout << "Display function of Base class" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Constructor of Derived class" << std::endl;
}
~Derived() {
std::cout << "Destructor of Derived class" << std::endl;
}
void display() override {
std::cout << "Display function of Derived class" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->display();
delete basePtr; // Calls destructor of Derived class first, then Base
return 0;
}
Output:
Constructor of Base class
Constructor of Derived class
Display function of Derived class
Destructor of Derived class
Destructor of Base class
Explanation: Virtual destructors ensure that the destructor of the derived class is called when an object is deleted through a base class pointer, preventing memory leaks and ensuring proper cleanup.
Step 4: Pure Virtual Functions and Abstract Class
A pure virtual function is a virtual function with no body, and an abstract class is a class that contains at least one pure virtual function.
#include <iostream>
class Shape { // Abstract class
public:
virtual void draw() = 0; // Pure virtual function
virtual ~Shape() {} // Virtual destructor
};
class Circle : public Shape { // Concrete class
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};
class Square : public Shape { // Concrete class
public:
void draw() override {
std::cout << "Drawing Square" << std::endl;
}
};
int main() {
Shape* shapes[2];
shapes[0] = new Circle();
shapes[1] = new Square();
for (int i = 0; i < 2; ++i) {
shapes[i]->draw(); // Polymorphism in action
delete shapes[i]; // Calls destructor of derived classes
}
return 0;
}
Output:
Drawing Circle
Drawing Square
Explanation:
In this example, Shape
is an abstract class with a pure virtual function draw()
. The derived classes Circle
and Square
provide concrete implementations of the draw()
function. This demonstrates how polymorphism and abstract classes can be used to design flexible and scalable code.
Conclusion
Top 10 Interview Questions & Answers on CPP Programming Function Overriding and Virtual Functions
Top 10 Questions and Answers on C++ Programming: Function Overriding and Virtual Functions
Answer: Function overriding in C++ occurs when a derived class has a function with the same name, return type, and parameters as a member function in the base (parent) class. The purpose of function overriding is to allow a derived class to provide a specific implementation for a function that is already defined in its base class. This mechanism supports polymorphism, enabling calls to the correct function based on the type of the object at runtime.
Example:
class Shape {
public:
virtual void draw() {
cout << "Drawing a generic shape." << endl;
}
};
class Circle : public Shape {
public:
void draw() override { // overriding Shape::draw()
cout << "Drawing a circle." << endl;
}
};
In this example, Circle
overrides the draw()
function from the Shape
class.
2. How is Function Overloading Different from Function Overriding?
Answer: Function overloading refers to multiple functions with the same name but different parameters or return types within the same class. On the other hand, function overriding involves defining a function in a derived class that has the exact same signature as a function in the base class, effectively replacing it during method calls.
Example:
Overloading:
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
};
Overriding:
class Base {
public:
virtual void display() {
cout << "Base class display function." << endl;
}
};
class Derived : public Base {
public:
void display() override {
cout << "Derived class display function." << endl;
}
};
In the overloading example, two add
functions have different parameter types, while in the overriding example, Derived::display
is a redefinition of Base::display
.
3. What is the use of the virtual
Keyword in C++?
Answer: The virtual
keyword in C++ is used to specify that a function in a base class is intended to be overridden by functions in derived classes. It enables dynamic dispatch, which refers to deciding at runtime which function to call based on the actual object's type, rather than the pointer/reference type.
4. Explain Runtime Polymorphism in C++ with an Example.
Answer: Runtime polymorphism in C++ is accomplished through inheritance and virtual functions. It allows a program to decide dynamically which function to call based on the concrete class of the object pointed/referenced at runtime.
Example:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() {
cout << "Animal makes a sound." << endl;
}
};
class Dog : public Animal {
public:
void sound() override {
cout << "Dog barks." << endl;
}
};
int main() {
Animal* p = new Dog();
p->sound(); // Output: Dog barks.
delete p;
return 0;
}
Here, sound()
is a virtual function in the Animal
class, thus allowing the main
function to determine the actual sound based on the object the pointer p
points to (Dog
, in this case).
5. Can Constructors and Destructors be Overridden in C++?
Answer: Constructors cannot be overridden in C++ because each class has a unique constructor corresponding to its class type that initializes its own data members. Destructors are virtual by default in derived classes if the base class destructor is virtual.
6. What are Pure Virtual Functions in C++?
Answer: Pure virtual functions make a class abstract, meaning no instances of this class can be created, and they must be implemented by non-abstract derived classes. They are declared with = 0
in their declaration within an abstract base class.
Example:
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
// Any class inheriting from Shape must implement 'draw'.
class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing rectangle." << endl;
}
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing circle." << endl;
}
};
7. What is a Virtual Destructor? Why is it Important?
Answer: A virtual destructor in a base class allows the destructor of the derived class to be called correctly through a base class pointer. Without a virtual destructor, deleting a derived class object via a base class pointer may lead to memory leaks or undefined behavior since only the base class destructor would be called.
Example:
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {
cout << "Base class destructor." << endl;
}
};
class Derived : public Base {
public:
~Derived() override {
cout << "Derived class destructor." << endl;
}
};
int main() {
Base* b = new Derived();
delete b; // Correctly calls both Derived and Base destructors
return 0;
}
8. What is the Difference Between Static and Dynamic Binding in C++?
Answer: Static binding occurs at compile time, where the method binding is determined by the type of the reference/pointer. Static binding is associated with compile-time polymorphism (function overloading).
Dynamic binding occurs at runtime, where the method binding is decided based on the content of the pointer/reference (i.e., the type of the actual object). Dynamic binding is linked with run-time polymorphism (function overriding through virtual functions).
9. When should you use Virtual Functions?
Answer: Virtual functions should be used when you anticipate the need for polymorphic behavior in your code. Specifically, when methods need to be overridden in derived classes, and function calls should be resolved dynamically based on the object's type to ensure the most appropriate method is invoked during execution.
10. Is it Possible to Override a Non-virtual Function in C++?
Answer: Though you can define a function with the same signature in a derived class, it is not considered an override of the base class function unless the base class function is marked as virtual
. If the base function is not virtual
, calling the function via a base class pointer will always invoke the base class version, regardless of the actual object pointed to.
Example:
class Base {
public:
void greet() {
cout << "Hello from Base class!" << endl;
}
};
class Derived : public Base {
public:
void greet() { // Not overriding, just hiding Base::greet()
cout << "Hello from Derived class!" << endl;
}
};
int main() {
Base* b = new Derived();
b->greet(); // Output: Hello from Base class!
delete b;
return 0;
}
In the above code snippet, Derived::greet
hides Base::greet
since the latter is not virtual, thus leading to the wrong function being called at runtime when using a base class pointer to a derived class object.
Login to post a comment.