Преобразование иерархии OO C ++ в процедурную C

Я использую C некоторое время, но иногда, когда я думаю о том, как решить проблему, я не могу думать ни о каком другом способе, кроме объектно-ориентированного подхода, как меня учили в школе. И поскольку я использовал C, я в основном использовал OO-шаблоны, но в C, иногда борясь с языком, чтобы заставить его работать. В качестве простого примера: если мне нужно написать абстракцию ресурсов файловой системы, я подумаю о написании базового класса Resource, который будет унаследован, например, классом ImageFile и классом AudioFile.

class Resource {
    bool opened;
    virtual bool load_file(const char *fpath);
    virtual bool release(void);
}

class ImageFile : Resource {
    bool load_file(const char *fpath) { ... }
    bool release(const char *fpath) { ... }
}

class AudioFile : Resource {
    bool load_file(const char *fpath) { ... }
    bool release(const char *fpath) { ... }
}

int main() {
    Resource img = ImageFile();
    Resource mus = AudioFile();

    img.load_file("my_image.png");
    mus.load_file("song.mp3");

    img.release();
    mus.release();

    return 0;
}

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


person aganm    schedule 12.03.2020    source источник
comment
Единственное, что близко к наследованию в C, - это использование общего заголовка на struct.   -  person Barmar    schedule 12.03.2020
comment
Но указатели на функции - это способ делать то, что вы пытаетесь сделать выше. Например, именно так драйверы устройств работают в ядре Unix: они представлены как объекты с набором указателей на функции для всех стандартных операций с устройствами.   -  person Barmar    schedule 12.03.2020


Ответы (1)


Ваша идея, ведущая к указателям на функции, определенно верный путь.

Идея состоит в том, что у нас есть указатели на функции «родительского» класса, дочерний класс имеет указатель на эту родительскую структуру, и мы, когда определяем собственное определение функций, можем указать эти функции на наши реализованные.

Я приведу вам простой пример того, как этого можно достичь.

struct resource {
    bool (*load_file)(const char *fpath);
    bool (*release)(const char *fpath)
};

struct imageFile {
    struct resource *ops;
};

struct audioFile {
    struct resource *ops;
};

bool image_load_file(const char *fpath) {...}
bool image_release(const char *fpath) {...}

bool audio_load_file(const char *fpath) {...}
bool audio_release(const char *fpath) {...}

int main () {
    static const struct op1 = {
        image_load_file,
        image_release,
    };

    static const struct op2 = {
        audio_load_file,
        audio_release,
    };

    // Assigning the functon pointers

    struct imageFile *im = malloc(sizeof(*im));
    im->ops = op1;

    struct audioFile *aud = malloc(sizeof(*aud));
    aud->ops = op2;

    // Calling the functions
    im->ops->load_file(fpath);
    im->ops->release(fpath);
}
person Pratik Sampat    schedule 12.03.2020