Подтвердить что ты не робот

C как объектно-ориентированный язык

Не могли бы вы предложить синтаксис для языка C, чтобы использовать его так же, как объектно-ориентированный язык? Я знаю, что они не могут быть одинаковыми и что некоторые ключевые слова не присутствуют на C, но мне интересно, есть ли способ использовать некоторые аспекты (например, наследование) даже в программе C.

4b9b3361

Ответ 1

Вы можете реализовать полиморфизм с помощью обычных функций и виртуальных таблиц (vtables). Вот довольно изящная система, которую я изобрел (на основе C++) для упражнения по программированию: alt text
(источник: goblin.tkk.fi)

Конструкторы выделяют память и затем вызывают функцию init класса, где память инициализируется. Каждая функция инициализации также должна содержать статическую структуру vtable, которая содержит указатели виртуальных функций (NULL для чисто виртуальных). Производные функции инициализации класса вызывают функцию инициализации суперкласса, прежде чем делать что-либо еще.

Очень хороший API может быть создан путем реализации виртуальных упаковщиков функций (не путать с функциями, указанными в vtables) следующим образом (добавьте static inline перед ним, если вы делаете это в заголовке):

int playerGuess(Player* this) { return this->vtable->guess(this); }

Одиночное наследование может быть сделано путем злоупотребления двоичным макетом структуры: alt text
(источник: goblin.tkk.fi)

Обратите внимание, что множественное наследование является более сложным, так как вам часто приходится корректировать значение указателя при приведении между типами иерархии.

Другие виртуальные таблицы также могут быть добавлены в виртуальные таблицы. Примеры включают информацию о типе среды выполнения (например, имя типа в виде строки), ссылки на vtable суперкласса и цепочку деструкторов. Возможно, вам нужны виртуальные деструкторы, в которых деструктор производного класса переводит объект в свой суперкласс, а затем рекурсивно вызывает деструктор этого и так далее, пока деструктор базового класса не будет достигнут и это в конечном итоге не освободит структуру.

Ответ 2

Существует библиотека GObject:

Система GLib Object или GObject - это библиотека бесплатного программного обеспечения (охватываемая LGPL), которая обеспечивает переносимую объектную систему и прозрачную межъязыковую совместимость. GObject предназначен для использования как непосредственно в программах на C, так и через привязки к другим языкам.

Ответ 3

Традиционное решение - это функция указателя struct. Я подчеркиваю традиционную. Я могу рассказать вам, какой код я написал в PL/I и C года назад, но я не утверждаю, что говорю о состоянии "искусства", если вы можете назвать это искусство.

В этом есть много вариантов, и ниже это немного компромисс.

struct SortOfAnAbstractClass {
   int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3);
   void (*function2)(SortOfAnAbstractClass* this, char *arg);
};

struct SortOfDerived {
   struct SortOfAnAbstractClass base;
   int instanceVariable1;
};

SortOfAnAbstractClass getMeOne() {
     SortOfDerived *d = malloc(sizeof SortOfDerived);
     memset(d, 0, sizeof SortOfDerived);
     d->function1 = myf1;
     d->function2 = myf2;
     return &d->base;
};

а затем "myf1" и "myf2" передают параметры 'this' и отправляются в город. Вы можете расширить его, чтобы он выглядел как полная виртуальная отправка.

Другая распространенная вариация от тумана времени:

struct SortOfAClass {
   void *creatorInfo;
   int (*function1)(SortOfAnAbstractClass* this, int arg1, int arg2, char * arg3);
   void (*function2)(SortOfAnAbstractClass* this, char *arg);
};

В этом варианте нет наследования путем включения. Производные классы помещают свое личное состояние в свой собственный объект в creatorInfo.

Ответ 5

Существует множество вариантов выполнения программирования OO в C. Способ, которым я предпочитаю это, - определить один класс для файла заголовка. Вы заметите конструктор new_testclass(), который только инициализирует ваши указатели на функции и возвращает указатель на выделенный класс /struct. Также любая функция принимает указатель на класс в первом параметре (что-то С++ делает, но скрывает).

testclass.h

#ifndef MALLOC_H
    #include<malloc.h>
#endif
struct _testclass 
{
    int a;
    int b;
    int (*sum)(struct _testclass *obj);
};

typedef struct _testclass testclass;

int f_sum (testclass *obj)
{
    return obj->a + obj->b;
}

testclass* new_testclass()
{
    testclass *temp;
    temp = (testclass*)malloc(sizeof(testclass));
    temp->sum = &f_sum;
    return temp;
}

Тогда вы можете просто использовать его.

testclass.c

#include <stdio.h>
#include "testclass.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int result;
    testclass *testclass1;
    testclass1 = new_testclass();
    testclass1->a = 5;
    testclass1->b = 8;
    result = testclass1->sum(testclass1);
    printf("%d\n",result);
    free(testclass1);
    return 0;
}

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