C как объектно-ориентированный язык - PullRequest
11 голосов
/ 28 февраля 2010

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

Ответы [ 5 ]

10 голосов
/ 28 февраля 2010

Вы можете реализовать полиморфизм с обычными функциями и виртуальными таблицами (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 голосов
/ 28 февраля 2010

Есть библиотека GObject :

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

2 голосов
/ 28 февраля 2010

Традиционным решением является структура указателя на функцию. Я подчеркиваю традиционный. Я могу сказать вам, какой код я написал в 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.

1 голос
/ 28 февраля 2010

Взгляните на библиотеку GObject: http://library.gnome.org/devel/gobject/2.22/.

0 голосов
/ 01 января 2013

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

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;
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...