Static Polymorphism

Compile time polymorphism.

1. Introduction

Static polymorphism in C++ is achieved using templates and compile-time mechanisms. Unlike dynamic polymorphism (achieved with inheritance and virtual functions), static polymorphism determines which function to call at compile time, resulting in better performance because there is no runtime overhead like virtual table lookups.

The most common method to achieve static polymorphism in C++ is through templates and CRTP (Curiously Recurring Template Pattern).

2. CRTP(Curiously Recurring Template Pattern)

CRTP is a design pattern where a derived class inherits from a base class that is templated on the derived class. This allows compile-time polymorphism with no runtime overhead.

CRTP.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

template <typename Derived>
class Base {
public:
void interface() {
// Call the derived class implementation
static_cast<Derived*>(this)->implementation();
}
};

class Derived : public Base<Derived> {
public:
void implementation() {
std::cout << "Derived implementation called." << std::endl;
}
};

int main() {
Derived d;
d.interface(); // Calls Derived::implementation
return 0;
}

Here is a more generic example.

shape.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>

// Base class template
template <typename Derived>
class Shape {
public:
void draw() {
// Call the derived class's implementation
static_cast<Derived*>(this)->draw();
}
};

// Derived class
class Circle : public Shape<Circle> {
public:
void draw() {
std::cout << "Drawing a Circle" << std::endl;
}
};

// Another derived class
class Square : public Shape<Square> {
public:
void draw() {
std::cout << "Drawing a Square" << std::endl;
}
};

int main() {
Shape<Circle> c;
Shape<Square> s;

c.draw(); // Outputs: Drawing a Circle
s.draw(); // Outputs: Drawing a Square

return 0;
}

3. Comparison with Dynamic Polymorphism

Feature Static Polymorphism Dynamic Polymorphism
Binding Time Compile-time Runtime
Implementation Templates, CRTP Virtual functions, inheritance
Performance Faster (no vtable lookup) Slower due to runtime overhead
Flexibility Limited (known types at compile time) Flexible (can use any derived type at runtime)

4. Conclusion

You should use static polymorphism when:

  • You need polymorphism but want to avoid the overhead of dynamic dispatch.
  • In scenarios where the type of objects involved is known at compile-time.
  • Your system is performance-critical.
Author

Joe Chu

Posted on

2024-11-24

Updated on

2024-11-26

Licensed under

Comments