LINUX.ORG.RU

Реализация методов в Си

 , ,


1

6

Всем привет!
Учу язык Си (не С++), дошёл до структур, и они мне так напомнили уже привычное ООП, с методами.
Решил, что можно ведь реализовать «Классы» и «Методы» и в обычном Си, объявляя указатели на функции в структурах.
Да, колхозно, да можно выбрать С++, а не Си. Но просто хотелось узнать мнение бывалых Си'шников, насколько это адекватный подход (1), и вообще делают ли так (2), и как можно улучшить написанный мной пример ниже (3)?:

#include <stdio.h>

int xsum(int x, int y);

int xsum(int x, int y)
{
        return x + y;
}

int main()
{

        struct point
        {
                int x;
                int y;
                int (*xysum)(int x, int y);
        };

        struct point pt;

        pt.x = 320;
        pt.y = 200;
        pt.xysum = &xsum;


        printf("X: %d\nY: %d\nSum: %d\n", pt.x, pt.y, pt.xysum(pt.x, pt.y));

        return 0;
}

Выводит:
X: 320
Y: 200
Sum: 520

  1. Неадекватный, но в сях по-другому не сделаешь;
  2. Делают, в том же ядре, например;
  3. Улучшить для чего?
XMs
()
Ответ на: комментарий от Zubok

Два чая этому господину. Смотри исходники и документацию к GLib и Gtk+, там как раз ООП на С во все поля.

hippi90
()

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

struct point;
struct point_methods {
  int (*abs)(struct point *);
  void (*translate)(struct point *,int dx,int dy);
};
struct point {
  struct point_methods *methods;
  int x,y;
};

MKuznetsov 👍👍👍
()

да... учебный год начался.(

mos
()

Лучше не объявлять указатели на функции в структурах, лишнюю память только занимаешь и производительность теряешь. Перегрузка методов нужна не всегда.

RisuX3
()
Ответ на: комментарий от Zubok

вот почему на ЛОРе темы не закрывают? сразу после этого поста и закрыть, впрочем такие темы вообще сразу надо грохать.

mos
()
Ответ на: комментарий от winston3d

Никак. В документации описать. Не надо перекладывать работу программиста на эвм.

RisuX3
()

в С++ есть первый «секретный» аргумент this, и когда ты ищеш переменную по имени, сперва её ищут в локальных переменных, затем смотрят в this, а только потом смотрят «вокруг» функции.

хочешь ООП? сам делай this.

struct foo {
};
void foo_method(struct foo * __restrict this, ...) {
} 
к слову, указатели в структуре тоже не используются. надо заводить еще одну структуру struct foo_vtable {} и там хранить указатели.

i36_zubov
()

ООП можно изображать даже на ассемблере. Проблема в том, что в этом случае никакой компилятор тебе не будет помогать отлавливать ошибки и избавлять от написания boilerplate кода.

asaw
()

объявляя указатели на функции в структурах.

Если тебе не нужны виртуальные методы, то зачем делать указатели на функции полями структур?

То есть смысл в указателях на функции в структуре имеется только в двух случаях:

  • тебе нужны колбеки;
  • тебе нужен обобщенный интерфейс, который надо дергать автоматом, не взирая на тип объектов.

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

shkolnick-kun
()
Ответ на: комментарий от shkolnick-kun

Всё это можно назвать двумя терминами: инкапсуляция и абстрагирование, чего ни препроцессор, ни компилятор Си обеспечить не могут (а препроцессор это вообще жесть, когд адело доходит до отладки). Код получается кишками наружу.

asaw
()
Ответ на: комментарий от asaw

инкапсуляция

Opaque data structures, не, не слышал...

абстрагирование

В смысле обобщенных интерфейсов? Делается на Си. Я даже «перегрузку функций» на прерпроцессоре делал работает, как часы.

shkolnick-kun
()
Ответ на: комментарий от shkolnick-kun

Если тебе не нужны виртуальные методы, то зачем делать указатели на функции полями структур?

Даже если они нужны, нет никакого смысла этого делать.

anonymous
()
Ответ на: комментарий от RazrFalcon

Отвечу постом из соседнего треда о Perl:

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

Нет.

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

uuwaan
()
Ответ на: комментарий от RazrFalcon

Потому что ситуация такая же. Если ты в C или в C++ описываешь структуру в хедере, то нету там никакой приватности, те самые кишки наружу. И единственный способ эти кишки не выставлять, что в Си, что C++ тоже одинаковый: opaque pointer, они же хэндлы, они же дескрипторы.

uuwaan
()
Ответ на: комментарий от shkolnick-kun

Я понимаю прекрасно. И ещё понимаю, что эта приватность эфемерна: берёшь приватное поле в заголовке и переносить из private в public. ЕМНИП, даже перекомпилять не надо, т.к. при мангле имени компилятор не учитывает приватность/публичность метода, если мы приватный метод переносим. Это что касается недобросовестного использования.

Добросовестное же состоит в использовании тех публичных методов, которые тебе даёт разработчик. Разработчик приватные поля Сишной структуры может объявить с подчёркиванием в имени, например. Или наклепать геттеров-сеттеров с атрибутом inline, точно так же как в C++.

uuwaan
()

pt.xysum = &xsum;

xsum — это уже указатель, так что можно без &.

pt.xysum(pt.x, pt.y)

По мне, так проще xysum(&pt).

anonymous
()
Ответ на: комментарий от mos

А ты, видимо, сразу такой умный родился. Как из мамки вылез, сразу давай на лор правильные посты строчить, да?

Вот почему на лоре таких мудаков как mos не грохают?

anonymous
()

Если виртуальных функций немного, то вполне можно, если много — имеет смысл добавить уровень косвенности и завести vtable. Существует мнение, что в таком случае стоит прекратить переизобретать кресты и имеет смысл писать на уже изобретённых.

Softwayer
()
Ответ на: комментарий от uuwaan

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

asaw
()
Ответ на: комментарий от uuwaan

Как «так можно сделать»? Наследование тебе компилятор сделает? Не сделает, ты его руками будешь делать в твоём Си через одно место, как ты и предложил.

asaw
()
Ответ на: комментарий от asaw

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

Прикинь, интерфейс можно реализовывать, не наследуясь от него.

uuwaan
()
Ответ на: комментарий от uuwaan

Так и записываем: «Сишка головного мозга».

приватность эфемерна

В сишке - да.

RazrFalcon
()
Ответ на: комментарий от uuwaan

Интерфейс – это вариант opaque pointer.

Никто и не спорит, что всё фичи современных языков можно изобразить в сишке тонной быдлокода с макросами. Но зачем?

RazrFalcon
()
Ответ на: комментарий от RazrFalcon

нету там никакой приватности

Советую вам изучить С++.

Это он так, со своей колокольни, вещает про #define private public.

И что, мол, от этого не спасет никакой private и остается только прозрачный указатель, который есть и в си...

Stil
()
Последнее исправление: Stil (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Никто и не спорит, что всё фичи современных языков можно изобразить в сишке тонной быдлокода с макросами. Но зачем?

Эм... Это C++ современный?

kirk_johnson
()

Решил, что можно ведь реализовать «Классы» и «Методы» и в обычном Си, объявляя указатели на функции в структурах.

В 1993 году мне мой руководитель диплома дал переводить статью, в которой как раз такой подход и описывался. Насколько я понимаю, GObject, который тут уже упоминали, тогда ещё не было. Но идея уже жила.

// Но диплом я всё же написал на крестах.

hobbit ☕☕☕☕☕
()
Ответ на: комментарий от uuwaan

У него ООП головного мозга. Сделаешь ему наследование, а он скажет что оно неправильное т.к. не такое как в С++.

Int0l
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.