C++ Interview Questions

22 Questions
C++ Programming

C++ Programming

Embedded SystemsIoTOther

Question 21

What is 'static polymorphism' in C++ and how does it differ from 'dynamic polymorphism'? Provide an example.

Answer:

Polymorphism is a core concept in object-oriented programming that allows objects to be treated as instances of their base class rather than their actual derived class. In C++, polymorphism can be achieved in two main ways: static polymorphism and dynamic polymorphism. Understanding the differences between these two types is crucial for designing efficient and flexible software systems.

Static Polymorphism:
Static polymorphism, also known as compile-time polymorphism, is achieved through template metaprogramming and function overloading. It is called 'static' because the decision about which function to call is made at compile time. This form of polymorphism is implemented using templates, which allow functions and classes to operate with generic types. Since the binding of function calls is done at compile time, static polymorphism can result in faster execution and reduced runtime overhead.

For example, consider the following template function that prints an object:

template<typename T>
void print(const T& obj) {
    obj.print();
}

class A {
public:
    void print() const { std::cout << "A"; }
};

class B {
public:
    void print() const { std::cout << "B"; }
};

int main() {
    A a;
    B b;
    print(a); // Outputs: A
    print(b); // Outputs: B
    return 0;
}

In this example, the print function template works with any type that has a print method. The compiler generates the appropriate function for each type used, resulting in efficient, type-safe code without the overhead of runtime polymorphism.

Dynamic Polymorphism:
Dynamic polymorphism, also known as runtime polymorphism, is achieved through inheritance and virtual functions. It is called 'dynamic' because the decision about which function to call is made at runtime based on the actual object type. This form of polymorphism is implemented using base classes with virtual functions, which are overridden in derived classes. The binding of function calls is done at runtime using a mechanism called the virtual table (vtable).

For example, consider the following class hierarchy using dynamic polymorphism:

class Base {
public:
    virtual void print() const { std::cout << "Base"; }
    virtual ~Base() = default; // Virtual destructor for proper cleanup
};

class DerivedA : public Base {
public:
    void print() const override { std::cout << "DerivedA"; }
};

class DerivedB : public Base {
public:
    void print() const override { std::cout << "DerivedB"; }
};

int main() {
    Base* a = new DerivedA();
    Base* b = new DerivedB();
    a->print(); // Outputs: DerivedA
    b->print(); // Outputs: DerivedB
    delete a;
    delete b;
    return 0;
}

In this example, the print method is virtual in the Base class and overridden in the DerivedA and DerivedB classes. The actual method called depends on the runtime type of the object pointed to by the Base pointer, demonstrating dynamic polymorphism.

Differences:
The primary difference between static and dynamic polymorphism lies in when the binding of function calls occurs. In static polymorphism, the binding is done at compile time, resulting in faster execution and no runtime overhead. However, it requires that the type of objects be known at compile time. In contrast, dynamic polymorphism allows for more flexibility since the binding is done at runtime, enabling the use of base class pointers or references to refer to objects of derived classes. This flexibility comes at the cost of runtime overhead due to the use of the vtable.

Use Cases:
Static polymorphism is preferred when performance is critical and the types of objects are known at compile time. It is commonly used in template-based libraries and generic programming. Dynamic polymorphism is preferred when the type of objects may vary at runtime and flexibility is required. It is commonly used in object-oriented design patterns and frameworks where the exact types of objects may not be known until runtime.

In summary, static polymorphism and dynamic polymorphism are two ways to achieve polymorphic behavior in C++. Static polymorphism is resolved at compile time using templates, resulting in faster execution and no runtime overhead. Dynamic polymorphism is resolved at runtime using inheritance and virtual functions, providing greater flexibility at the cost of some performance overhead. Understanding the differences and appropriate use cases for each type of polymorphism is essential for designing efficient and flexible software systems in C++.

Recent job openings