Overview
Polymorphism in C++ is a foundational concept in object-oriented programming that allows methods to do different things based on the object that is calling them. It enhances code flexibility and readability, making it a crucial topic for C++ developers.
Key Concepts
- Compile-Time Polymorphism: Achieved through function overloading and operator overloading.
- Run-Time Polymorphism: Implemented using virtual functions, allowing method overriding.
- Ad-hoc Polymorphism: Specific cases of polymorphism, often achieved through function overloading.
Common Interview Questions
Basic Level
- What is polymorphism in C++, and why is it important?
- Explain function overloading in C++.
Intermediate Level
- How does run-time polymorphism work in C++?
Advanced Level
- Discuss the impact of polymorphism on system performance and how to optimize its usage in C++.
Detailed Answers
1. What is polymorphism in C++, and why is it important?
Answer: Polymorphism in C++ allows functions or operators to behave differently based on the context, such as the types or number of arguments passed to them. It's important because it enhances the flexibility and maintainability of code by allowing a single interface to represent different underlying forms (data types or classes).
Key Points:
- Enhances code readability and reuse.
- Supports the implementation of inheritance hierarchies.
- Facilitates dynamic (run-time) binding.
Example:
// Compile-time polymorphism example with function overloading
#include <iostream>
using namespace std;
class Print {
public:
void show(int i) {
cout << "Integer: " << i << endl;
}
void show(double d) {
cout << "Double: " << d << endl;
}
};
int main() {
Print p;
p.show(10); // Calls the function with the int parameter
p.show(10.5); // Calls the function with the double parameter
return 0;
}
2. Explain function overloading in C++.
Answer: Function overloading in C++ is a form of compile-time polymorphism where multiple functions can have the same name with different parameters (either in number, order, or type). It allows functions to perform similar operations on different types or numbers of inputs.
Key Points:
- Increases the readability of the code.
- Each overloaded function must have a unique signature.
- Resolved at compile time, hence also known as static binding.
Example:
// Function overloading example
#include <iostream>
using namespace std;
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
}
int main() {
print(10); // Calls print(int)
print(10.10); // Calls print(double)
print("A"); // Calls print(char*)
return 0;
}
3. How does run-time polymorphism work in C++?
Answer: Run-time polymorphism in C++ is achieved through virtual functions and inheritance. A virtual function in a base class is overridden in a derived class to perform different actions. This allows for dynamic binding, where the call to an overridden function is resolved at run-time.
Key Points:
- Enables dynamic (late) binding.
- Uses pointer or reference of base class type to invoke methods.
- Virtual functions allow derived classes to customize or replace implementation.
Example:
// Run-time polymorphism with virtual functions
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() {
cout << "Base class show function called." << endl;
}
};
class Derived : public Base {
public:
void show() {
cout << "Derived class show function called." << endl;
}
};
int main() {
Base* bptr;
Derived d;
bptr = &d;
bptr->show(); // Calls Derived class function
return 0;
}
4. Discuss the impact of polymorphism on system performance and how to optimize its usage in C++.
Answer: Polymorphism, especially run-time polymorphism, can impact system performance due to the overhead of dynamic binding. Virtual function calls are slower than direct function calls because of the vtable lookup. However, the design flexibility and maintainability benefits often outweigh the performance costs. To optimize, minimize the use of virtual functions in performance-critical paths, use final specifier in C++11 to prevent further overriding, and consider alternatives like templates for compile-time polymorphism which has no run-time overhead.
Key Points:
- Virtual functions introduce runtime overhead.
- Use final
specifier for classes or functions that shouldn't be overridden.
- Prefer compile-time polymorphism (templates) for critical sections.
Example:
// Minimizing virtual function overhead
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() final { // Preventing further overriding
cout << "Base class show function called." << endl;
}
};
class Derived : public Base {
// Error: cannot override 'final' function "Base::show"
void show() {
cout << "Derived class show function called." << endl;
}
};
int main() {
// Your code to demonstrate or explanation
return 0;
}
Note: The example under advanced level demonstrates the concept with the final
specifier, however, the actual compilation will fail due to an attempt to override a final
function.