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 ★★★★★ ()
Ответ на: комментарий от RisuX3

А как иначе можно сделать доступ к функции через её «родителя» так сказать..?

winston3d ()
Ответ на: комментарий от 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

Пример невозможной инкапсуляции в Си приведи, пожалуйста.

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

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

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

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

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

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

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

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

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

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

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

Нет.

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

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

Я не просил private, я просил приватную переменную, для инкапсуляции.

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

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

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

Имеется в виду, что в крестах private доступны только самому классу и френдам, а в Си...

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

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

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

uuwaan ★★ ()

pt.xysum = &xsum;

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

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

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

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

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

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

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

Бред собачий. В C++ есть как минимум ещё интерфейсы и наследование.

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

Интерфейс – это вариант opaque pointer. Причём здесь наследование в контексте сокрытия приватных членов, я не понял.

uuwaan ★★ ()

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

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

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

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

Это и в Си так можно сделать. Что сказать-то хотел?

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

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

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

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

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

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

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

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

В сишке - да.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Да вот в С++20 как концепты с модулями завезут, так сразу современнее всех будет!

Softwayer ★★ ()

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

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

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

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

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

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