Полиморфизм (в кл)

Возможный дубликат:
Как я могу симулировать полиморфизм ОО-стиля в C?

Я пытаюсь лучше понять идею полиморфизма на примерах из известных мне языков; есть ли полиморфизм в C?

4 ответа

Решение

Это второй пример Nekuromento, основанный на способе, который я считаю идиоматическим для объектно-ориентированного C:

animal.h

#ifndef ANIMAL_H_
#define ANIMAL_H_

struct animal
{
    // make vtable_ a pointer so they can be shared between instances
    // use _ to mark private members
    const struct animal_vtable_ *vtable_;
    const char *name;
};

struct animal_vtable_
{
    const char *(*sound)(void);
};

// wrapper function
static inline const char *animal_sound(struct animal *animal)
{
    return animal->vtable_->sound();
}

// make the vtables arrays so they can be used as pointers
extern const struct animal_vtable_ CAT[], DOG[];

#endif

cat.c

#include "animal.h"

static const char *sound(void)
{
    return "meow!";
}

const struct animal_vtable_ CAT[] = { { sound } };

dog.c

#include "animal.h"

static const char *sound(void)
{
    return "arf!";
}

const struct animal_vtable_ DOG[] = { { sound } };

main.c

#include "animal.h"
#include <stdio.h>

int main(void)
{
    struct animal kitty = { CAT, "Kitty" };
    struct animal lassie = { DOG, "Lassie" };

    printf("%s says %s\n", kitty.name, animal_sound(&kitty));
    printf("%s says %s\n", lassie.name, animal_sound(&lassie));

    return 0;
}

Это пример полиморфизма во время выполнения, когда происходит разрешение метода.

C1x добавил общие выделения, которые делают возможным полиморфизм во время компиляции через макросы. Следующий пример взят из апрельского черновика C1x, раздел 6.5.1.1 §5:

#define cbrt(X) _Generic((X), \
    long double: cbrtl, \
    default: cbrt, \
    float: cbrtf \
)(X)

Типовые макросы для математических функций уже были доступны в C99 через заголовок tgmath.h, но у пользователей не было возможности определять свои собственные макросы без использования расширений компилятора.

Почти во всех реализациях полиморфизма времени выполнения в C будут использоваться указатели функций, так что это основной строительный блок.

Вот простой пример, когда поведение во время выполнения процедуры изменяется в зависимости от ее аргумента.

#include <stdio.h>

int tripple(int a) {
    return 3 * a;
}

int square(int a) {
    return a * a;
}

void transform(int array[], size_t len, int (*fun)(int)) {
    size_t i = 0;
    for(; i < len; ++i)
        array[i] = fun(array[i]);
}

int main() {
    int array[3] = {1, 2, 3};
    transform(array, 3, &tripple);
    transform(array, 3, &square);

    size_t i = 0;
    for (; i < 3; ++i)
        printf("%d ", array[i]);

    return 0;
}

Используя указатели на функции, вы можете создавать виртуальные таблицы и использовать их для создания "объектов", которые будут обрабатываться единообразно, но вести себя по-разному во время выполнения.

#include <stdio.h>

struct animal_vtable {
    const char* (*sound)();
};

struct animal {
    struct animal_vtable methods;
    const char* name;
};

const char* cat_sound() {
    return "meow!";
}

const char* dog_sound() {
    return "bark!";
}

void describe(struct animal *a) {
    printf("%s makes \"%s\" sound.\n", a->name, a->methods.sound());
}

struct animal cat = {{&cat_sound}, "cat"};
struct animal dog = {{&dog_sound}, "dog"};

int main() {
    describe(&cat);
    describe(&dog);

    return 0;
}

В C нет встроенной поддержки полиморфизма, но есть шаблоны проектирования, использующие указатели функций, приведение базовых классов (структур) и т. Д., Которые могут обеспечить логический эквивалент динамической диспетчеризации. Библиотека GTK является хорошим примером.

Я думаю, вы уже проверили статью в Википедии о полиморфизме.

В информатике полиморфизм - это особенность языка программирования, которая позволяет обрабатывать значения разных типов данных с использованием единого интерфейса.

Согласно этому определению, нет, C изначально не поддерживает полиморфизм. Например, нет общей функции для получения абсолютного значения числа (abs а также fabs для целых и двойных соответственно).

Если вы также знакомы с C++, взгляните на наследование ООП и шаблоны - это механизмы полиморфизма.

Другие вопросы по тегам