Nano Hash - криптовалюты, майнинг, программирование

Какие методы / стратегии люди используют для создания объектов на C (не C ++)?

Меня особенно интересуют объекты, предназначенные для использования изнутри C, в отличие от реализаций объектов, которые составляют ядро ​​интерпретируемых языков, таких как python.

04.08.2009

  • Хотя я всегда использовал то, что, как я полагаю, можно было бы назвать объектно-ориентированным стилем программирования на C, это намного проще (и почти все остальное) на C ++. Я должен спросить, почему ты, кажется, не хочешь его использовать? 04.08.2009
  • @Neil: Если бы не было причин, не было бы GObject. Есть много причин для C: устаревшие платформы, надежность, двоичная совместимость с ABI и т. Д. 04.08.2009
  • @EFraim Мне хорошо известны эти причины, но я спрашивал, каковы были причины спрашивающего. 04.08.2009
  • @Niel - нежелание вводить C ++ в качестве зависимости должно быть достаточной причиной. Кроме того, есть много умных решений ... Я бы хотел увидеть их здесь задокументированные / сравненные. 04.08.2009

Ответы:


1

Я обычно делаю что-то вроде этого:

struct foo_ops {
    void (*blah)(struct foo *, ...);
    void (*plugh)(struct foo *, ...);
};
struct foo {
    struct foo_ops *ops;
    /* data fields for foo go here */
};

С этими определениями структуры код, реализующий foo, выглядит примерно так:

static void plugh(struct foo *, ...) { ... }
static void blah(struct foo *, ...) { ... }

static struct foo_ops foo_ops = { blah, plugh };

struct foo *new_foo(...) {
   struct foo *foop = malloc(sizeof(*foop));
   foop->ops = &foo_ops;
   /* fill in rest of *foop */
   return foop;
} 

Затем в коде, который использует foo:

struct foo *foop = new_foo(...);
foop->ops->blah(foop, ...);
foop->ops->plugh(foop, ...);

Этот код можно привести в порядок с помощью макросов или встроенных функций, чтобы он выглядел более похожим на C.

foo_blah(foop, ...);
foo_plugh(foop, ...);

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

Этот метод полностью подходит для реализации относительно простых объектно-ориентированных проектов на C, но он не обрабатывает более сложные требования, такие как явное представление классов и наследование методов. Для них вам может понадобиться что-то вроде GObject (как упоминал EFraim), но я бы посоветовал убедиться, что вам действительно нужны дополнительные функции более сложных фреймворков.

04.08.2009

2

Вы используете термин «объекты» немного расплывчато, поэтому я предполагаю, что вы спрашиваете, как использовать C для достижения определенных аспектов объектно-ориентированного программирования (не стесняйтесь поправлять меня в этом предположении).

Полиморфизм метода:

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

struct image_scaler {
    //member variables
    int (*scale)(int, int, int*);
}

Затем я мог бы сделать несколько таких программ масштабирования изображений:

struct image_scaler nn, bilinear;
nn->scale = &nearest_neighbor_scale;
bilinear->scale = &bilinear_scale;

Это позволяет мне добиться полиморфного поведения для любой функции, которая принимает image_scaler и использует его метод масштабирования, просто передавая ему другой image_scaler.

Наследование

Наследование обычно достигается как таковое:

struct base{
   int x;
   int y;
} 

struct derived{
   struct base;
   int z;
}

Теперь я могу свободно использовать производные дополнительные поля вместе с получением всех «унаследованных» полей базы. Кроме того, если у вас есть функция, которая принимает только структуру base. вы можете просто преобразовать указатель struct dervied в указатель struct base без каких-либо последствий

04.08.2009
  • Спасибо, Falain (я проголосовал за). Не могли бы вы указать на библиотеку, которая делает это, чтобы я или кто-либо другой мог изучить всю реализацию? 04.08.2009

  • 3

    Библиотеки, такие как GObject.

    По сути, GObject предоставляет общий способ описания непрозрачных значений (целых чисел, строк) и объектов (путем ручного описания интерфейса - как структуры указателей на функции, в основном соответствующих VTable в C ++) - более подробную информацию о структуре можно найти в его < href = "http://library.gnome.org/devel/gobject/stable/gtype-instantiable-classed.html" rel = "nofollow noreferrer"> справочник

    Вы также часто вручную реализуете vtables, как в "COM на простом C"

    04.08.2009
  • EFraim - Не могли бы вы описать стратегию реализации GObject в своем ответе, чтобы мы могли сравнить ее с некоторыми другими предоставленными решениями? 04.08.2009

  • 4

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

    Однако я обнаружил, что ОЧЕНЬ важным аспектом программного обеспечения является удобочитаемость. Вы пробовали читать код 10-летней давности? В результате я предпочитаю использовать самый простой подход, когда делаю такие вещи, как объекты на C.

    Спросите следующее:

    1. Это для клиента с крайним сроком (если да, рассмотрите ООП)?
    2. Могу ли я использовать ООП (часто меньше кода, быстрее в разработке, более читабельно)?
    3. Могу ли я использовать библиотеку (существующий код, существующие шаблоны)?
    4. Я ограничен памятью или процессором (например, Arduino)?
    5. Есть ли еще одна техническая причина использовать C?
    6. Могу ли я сделать мой C очень простым и читабельным?
    7. Какие функции ООП мне действительно нужны для моего проекта?

    Обычно я возвращаюсь к чему-то вроде API GLIB, который позволяет мне инкапсулировать мой код и обеспечивает очень читаемый интерфейс. Если нужно больше, я добавляю указатели на функции для полиморфизма.

    class_A.h:
      typedef struct _class_A {...} Class_A;
      Class_A* Class_A_new();
      void Class_A_empty();
      ...
    
    #include "class_A.h"
    Class_A* my_instance;
    my_instance = Class_A_new();
    my_instance->Class_A_empty();  // can override using function pointers
    
    14.08.2013

    5

    Посмотрите на реализацию IJG. Они не только используют setjmp / longjmp для обработки исключений, у них есть vtables и все такое. Это хорошо написанная и достаточно маленькая библиотека, чтобы вы могли получить очень хороший пример.

    04.08.2009
  • Вы знаете, используют ли они реализацию, подобную предложенной Дейлом и Фалаиной? Или что-то более динамичное? 04.08.2009

  • 6

    Подобно подходу Дейла, но в большей степени PostgreSQL представляет внутренние узлы дерева синтаксического анализа, типы выражений и тому подобное. По умолчанию используются структуры Node и Expr, аналогичные строкам

    typedef struct {
        NodeTag n;
    } Node;
    

    где NodeTag - это typedef для unsigned int, и есть файл заголовка с набором констант, описывающих все возможные типы узлов. Сами узлы выглядят так:

    typedef struct {
        NodeTag n = FOO_NODE;
        /* other members go here */
    } FooNode;
    

    и FooNode может быть безнаказанно преобразован в Node из-за причуды структур C: если две структуры имеют идентичные первые члены, они могут быть преобразованы друг в друга.

    Да, это означает, что FooNode можно преобразовать в BarNode, чего вы, вероятно, не хотите делать. Если вам нужна правильная проверка типов во время выполнения, GObject - это то, что вам нужно, хотя будьте готовы ненавидеть жизнь, пока вы ее осваиваете.

    (примечание: примеры из памяти, я давно не разбирался во внутренностях Postgres. FAQ для разработчиков есть дополнительная информация.)

    04.08.2009
  • Давным-давно (около 1988 г.) я работал над компилятором C, где узлы синтаксического анализа представляли собой битовое объединение отдельных типов узлов с тегом типа вне объединения, чтобы решить, какая ветвь объединения действительна: это морально эквивалентно тому, что вы описывать. Сегодня я почти наверняка сделаю это в соответствии с моим предложением выше. Я обнаружил, что использование указателей на функции действительно заставляет меня определять желаемый общедоступный API - поскольку вызывающий не знает имени вызываемой функции, ему очень трудно пройти мимо этой функции, чтобы использовать внутренние данные о реализации. 07.08.2009
  • Вздох ... s / bit union / big union / в вышеизложенном. Извините за опечатку. 07.08.2009
  • Подход с указателем на функцию определенно превосходит его - во-первых, он позволяет вам приближать методы привязки к объекту. Мне нравятся ваши примеры, и я проголосовал за них. 07.08.2009
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..