Programación orientada a objetos en C: estructuras y punteros

1. Introduction

El lenguaje C, debido a su contexto histórico y su control a bajo nivel, es muy apreciado por muchos programadores. Sin embargo, el lenguaje C no es un «lenguaje orientado a objetos». Es decir, a diferencia de Java o C++, el propio lenguaje no soporta características de orientación a objetos (clases, herencia, encapsulación, etc.). No obstante, incluso en C es posible imitar los conceptos de programación orientada a objetos y lograr cierta funcionalidad. En este artículo, explicaremos paso a paso los conceptos básicos como encapsulación, herencia y polimorfismo, y cómo implementar la programación orientada a objetos en C.

2. Conceptos básicos de la programación orientada a objetos

La programación orientada a objetos (OOP) tiene como objetivo gestionar los datos y sus métodos de forma integrada. Esto hace que la estructura del programa sea más clara y mejora la reutilización y el mantenimiento. Los conceptos principales de la programación orientada a objetos son encapsulamiento, herencia y polimorfismo. El lenguaje C no los soporta directamente, pero es posible reproducirlos de forma simulada con ingenio.

2.1 Encapsulamiento

El encapsulamiento consiste en agrupar los datos y sus operaciones (métodos) en una única unidad y controlar el acceso externo. En C, se pueden usar estructuras para agrupar datos. Las estructuras cumplen una función similar a las clases, al reunir varios datos en una sola entidad.
typedef struct {
    int age;
    char name[50];
} Person;
En esta estructura, el tipo de datos Person encapsula la información de edad y nombre. De este modo, es posible instanciar y manipular Person.

2.2 Herencia

El lenguaje C no posee el concepto de herencia, por lo que no se pueden crear relaciones padre-hijo como en las clases. Sin embargo, usando estructuras y anidando una estructura dentro de otra como miembro, se puede lograr un mecanismo similar a la herencia.
typedef struct {
    int age;
} Parent;

typedef struct {
    Parent parent;
    int studentID;
} Child;
En este código, la estructura Child contiene a la estructura Parent, representando una herencia simulada.

2.3 Polimorfismo

El polimorfismo se refiere a la capacidad de que una misma operación produzca comportamientos diferentes según el tipo de objeto. En C, este concepto se puede implementar mediante punteros a funciones. Un puntero a función es una variable que almacena la dirección de una función y permite invocar dinámicamente distintas funciones.
typedef int (*OperationFunc)(int, int);

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

OperationFunc op = add;  // establecer la función add como puntero
printf("%d", op(3, 4));  // resultado: 7
op = multiply;            // cambiar a la función multiply
printf("%d", op(3, 4));   // resultado: 12
De esta manera, se pueden realizar diferentes operaciones utilizando el mismo puntero a función.
年収訴求

3. Cómo implementar clases en C

Para lograr programación orientada a objetos en C, es necesario crear de forma simulada el concepto de clase. Para ello, se combinan estructuras y punteros a funciones para crear una estructura similar a una clase.

3.1 Usar estructuras como clases

Para implementar clases en C, se utilizan estructuras, agrupando datos y métodos como en una clase. Los métodos se definen como funciones y se gestionan dentro de la estructura mediante punteros a funciones.
typedef struct {
    int age;
    void (*setAge)(struct Person*, int);
    int (*getAge)(struct Person*);
} Person;

void setAge(struct Person* p, int age) {
    p->age = age;
}

int getAge(struct Person* p) {
    return p->age;
}

Person person = {0, setAge, getAge};
person.setAge(&person, 25);
printf("Age: %d", person.getAge(&person));  // Resultado: 25
En este código, la estructura Person tiene los métodos setAge y getAge, y funciona de forma similar a una clase.

4. Implementación de métodos

Para reproducir los «métodos», una característica de la programación orientada a objetos, en C, se utilizan punteros a funciones. De este modo, se pueden definir métodos como variables miembro de una estructura.
typedef struct {
    int age;
    void (*setAge)(struct Person*, int);
} Person;

void setAge(struct Person* p, int age) {
    p->age = age;
}

5. Resumen y Aplicaciones

Es posible implementar la programación orientada a objetos en C, pero como el lenguaje en sí no lo soporta, se requiere cierta ingeniosidad. Al aprovechar estructuras, punteros a funciones y la gestión de memoria, se pueden incorporar de forma simulada los conceptos de clases y herencia.