Implementation Methods and Examples of Polymorphism in C Language

Implementation Methods and Examples of Polymorphism in C Language

In object-oriented programming, polymorphism is an important concept that allows the same method to be called in different forms through various means. In C language, although there is no direct syntax support for polymorphism, we can achieve similar effects through the following methods: function pointers, combinations of structures and unions, and interface simulation. This article will detail these implementation methods and provide practical examples.

Method 1: Function Pointers

Function pointers allow us to pass a function as a parameter to another function, enabling the dynamic selection of specific functionalities at runtime. Below is an example where multiple operations can be selected at runtime:

#include <stdio.h>
// Define operation type
typedef int (*operation_func)(int, int);
// Addition operation
int add(int a, int b) {    return a + b;}
// Subtraction operation
int subtract(int a, int b) {    return a - b;}
// Calculator that selects a specific operation
int calculator(int x, int y, operation_func op) {    return op(x, y);}
int main() {    int a = 10;     int b = 5;
    // Using addition    printf("Addition: %d\n", calculator(a, b, add));
    // Using subtraction    printf("Subtraction: %d\n", calculator(a, b, subtract));
    return 0;}

Explanation:

  1. We defined a type called <span>operation_func</span> that represents a function pointer with two integer parameters returning an integer result.
  2. Implemented the <span>add</span> and <span>subtract</span> functions, both conforming to this type.
  3. In the <span>calculator</span> function, the specific algorithm to execute is determined by the passed operator (i.e., different expressions).
  4. In the <span>main</span> function, addition or subtraction is dynamically selected based on the requirement.

Method 2: Combinations of Structures and Unions

We can combine structures and unions to create custom data types that simulate object-oriented features and polymorphism:

#include <stdio.h>
// Define shape base class (can be viewed as an interface)
typedef struct Shape {    void (*draw)(struct Shape* self);} Shape;
// Circle class, implementing draw method
typedef struct Circle {    Shape base; // Base class part} Circle;
void draw_circle(Shape* self) {   printf("Drawing Circle\n");}
// Rectangle class, implementing draw method
typedef struct Rectangle {   Shape base; // Base class part } Rectangle;
void draw_rectangle(Shape* self) {   printf("Drawing Rectangle\n");}
void render(Shape* shape) {     if (shape && shape->draw) {        shape->draw(shape);      }}
int main() {       Circle circle = {{draw_circle}};        Rectangle rectangle = {{draw_rectangle}};   
     render((Shape*)&circle);       render((Shape*)&rectangle);  
     return 0;}

Explanation:

  1. A structure named <span>Shape</span> is defined as a base class, which contains a function pointer field pointing to the draw method (<span>draw</span>).
  2. New structures for Circle (<span>Circle</span>) and Rectangle (<span>Rectangle</span>) are created, both inheriting from <span>Shape</span>.
  3. They implement their own drawing logic, and in the main program, they are called through type casting to demonstrate polymorphic behavior.

Method 3: Interface Simulation

In some cases, you may want to use abstract interface methods for further encapsulation, which is essentially an extension of the above ideas. Typically, the goal is to demonstrate this design pattern in more complex or larger software architectures.

For well-planned systems, multiple components can be built based on common API models. For example, we ensure that the API documentation specifies all methods that must be followed, and clients need to ensure they can call these methods. However, since C is a compiled language, this example omits that aspect to reduce complexity, only illustrating how to establish a modular solution using ADT (Abstract Data Type) combined with callbacks:

The example code is as shown above and will be referenced again (for readability).

Ultimately, regardless of the means employed, each strategy creates opportunities for your software architecture to be more flexible, allowing for runtime code changes and extensibility rather than relying on static compile-time links. By effectively utilizing fundamental features, we can achieve elegant and concise designs!

I hope this article helps you understand polymorphism in C language and its implementation methods. If you have any further questions, please feel free to ask.

Leave a Comment