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

Если подумать смысла особого в инкапсуляции нету. Какая разница что писать.

xsum(pt);
или
pt.xsum(pt);

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

Вообще, просто синтаксис вызова метода. Инкапсуляция - это сокрытие данных, и то как вызывается метод к ней не имеет отношения.

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

Инкапсуляция - это языковая конструкция, которая облегчает группирование данных с методами (функциями), работающими с этими данными.

Int0l ★★
()
Последнее исправление: Int0l (всего исправлений: 2)
Ответ на: комментарий от Softwayer

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

Их уже пытались завести сперва в 14, а потом и в 17 стандарт. Как видишь, до сих пор имеем дрочилово на хидеры.

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

Инкапсуля́ция (лат. in capsula) — размещение в оболочке, изоляция, закрытие чего-либо инородного с целью исключения влияния на окружающее. Например, поместить радиоактивные отходы в капсулу, закрыть кожухом механизм, убрать мешающее в ящик или шкаф.

kirk_johnson ★☆
()
Ответ на: комментарий от Int0l
(define (point x y)
  (lambda (selector)
    (cond ((eq? selector 'x) x)
          ((eq? selector 'y) y)
          (else (error "invalid selector " selector)))))
(define p (point 1 2))
(p 'x)
(p 'y)
Begemoth ★★★★★
()
Ответ на: комментарий от Int0l

Так можно дойти до того, что замыкания это тоже инкапсуляции.

давненько хотел услышать простое определение замыкания, не поможете? не расскажите ли ??

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

У понятия инкапсуляция есть несколько определений.

Int0l ★★
()

ТС, переходи на Objective-C и Clang.

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

Если подумать смысла особого в инкапсуляции нету.

Подумайте лучше. Синтаксис вызова методов тут не при чём.

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

Инкапсуляция - это языковая конструкция, которая облегчает группирование данных с методами (функциями), работающими с этими данными.

Кстати, даже исходя из такого определения, то все равно это не имеет отношения к синтаксису вызова метода - foo.bar() или bar(foo).

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

А у тебя? Ты же не понимаешь, что такое инкапсуляция. По-моему это всем очевидно всем в этом треде.

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

Читайте тред. Там всё было. Единственное, что здесь видно, это любовь сишников изобретать велосипеды, вместо использования готовых инструментов.

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

private в C++ – это всего лишь напоминалка, что вот те поля и методы – не трогать. Если ты это сделаешь, на тебя по ругается компилятор. Как стикер на мониторе. Его можно сорвать, а этот private можно заменить на public, и даже перекомпилировать код необязательно.

Более надёжный способ защитить, если это надо, – не палить приватные поля и методы в заголовочном файле вообще.

Так что в плане механики Си и C++ на равных. Единственное отличие – в Си это джентельменское соглашение, не лезть в поля структуры, если есть вариант использовать API, а C++ бьёт тебя по рукам в любом случае. По мне так это преимущество на уровне, что кто-то не писает мимо толчка самостоятельно, а кому-то приходится постоянно делать замечания.

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

Инкапсуляция
...
Информатика, программирование — обеспечение доступности главного, выделение основного содержания путём помещения всего мешающего, второстепенного в некую условную капсулу (чёрный ящик).

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

А я оспариваю ваши доводы и согласен с автором того поста. В Си нет инкапсуляции.

Тебе уже сказали про opaque pointer'ы. Что тебе ещё непонятно, прости господи?

https://en.wikipedia.org/wiki/Opaque_pointer#C

This example demonstrates a way to achieve the information hiding (encapsulation) aspect of object-oriented programming using the C language. If someone wanted to change the declaration of struct obj, it would be unnecessary to recompile any other modules in the program that use the obj.h header file unless the API was also changed. Note that it may be desirable for the functions to check that the passed pointer is not NULL, but such checks have been omitted above for brevity.

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

У вас странное представление об private.

не палить приватные поля и методы

Вы опять не понимаете разницы между private и данными/методами, «которые не видны». Какая разница видит ли пользователь либы описание структуры в хедере или нет. Если я пометил поля как private, они для него private. Не нужны никакие «джентельменские соглашения» и прочая муть.

Я доволен тем, что компилятор делает за меня рутинную работу.

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

Вы почитайте на какое сообщения я отвечал.

А ты почитай, на какое я отвечал.

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

``в с++ нет инкапсуляции" (уверен, так можно сделать даже в жабе)

#include <iostream>

class Test
{
private:
  int x;
  int y;
public:
  Test(int x, int y) { this->x = x; this->y = y; }
  ~Test() {}
  int get_x() const { return this->x; }
  int get_y() const { return this->y; }
};


int
main(int argc, char *argv[])
{
  Test test (1,2);

  std::cout << test.get_x() << std::endl;

  *(reinterpret_cast<int*>(&test)) = 12;

  std::cout << test.get_x() << std::endl;
  
  return 0;
}

opaque structures — вполне себе инкапсуляция. Инкапсуляция, она скорее про отношение к данным, а не про механихм доступа к ним. Если абстрагируешься от полей — вполне себе инкапсуляция. Но это все, конечно, беспредметный спор о понятиях без конкретных определений.

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

Товарищ считает, что если ему компилятор говорит: «Атата, не лезь в это поле, оно приватное!», то это уже инкапсуляция. При этом любое изменение любой такой «инкапсулированной» сущности потребует перекомпиляции всего клиентского кода. Что ж, это распространённое мнение.

У меня более радикальный взгляд: инкапусляция – это когда не видно, не слышно, и клиентский код пересобирать не надо.

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

Товарищ считает, что если ему компилятор говорит: «Атата, не лезь в это поле, оно приватное!», то это уже инкапсуляция. При этом любое изменение любой такой «инкапсулированной» сущности потребует перекомпиляции всего клиентского кода. Что ж, это распространённое мнение.

Ах.

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

В C++, если поля private, то их всё равно можно иметь к ним прямой доступ зная смещение.

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

Я доволен тем, что компилятор делает за меня рутинную работу

Вот так и сказали бы сразу: «Мне нравится, что компилятор за мной проверяет». Ничего постыдного в этом нет.

Но вы же начали поддерживать точку зрения, что в Си инкапсуляции нет физически. Вот это неправда, на физическом уровне C и C++ одинаковы. С таким же успехом могли бы в C добавить какую-нибудь сферическую #pragma private(member_name) и получить «инкапсуляцию» уровня private в C++.

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

«которые не видны»

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

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

на физическом уровне C и C++ одинаковы

На физическом - все одинаковы. Только толку от этого разработчику?

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

Ну тогда и сокрытие данных не имеет отношение к инкапсуляции.

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

Читайте тред

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

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

Ну в нормальной библиотеке будет соглашение, что все операции над структурой - только через специальные функции (некоторых из которых могут быть inline, скажем, всякие геттеры и сеттеры), а прямой доступ к полям структуры - недокументированная фича (а набор полей может быть изменён в любой версии, в отличии от API, которое типа стабильно). Тоже вполне себе инкапсуляция.

Ещё можно не описывать структуру в заголовочном файле вообще. Или описать в виде массива char нужного размера. А реальное описание полей делать лишь внутри файла реализации библиотеки. А все функции принимают void* или указатель на массив. Тогда прямой доступ к полям структуры будет ещё более затруднён, чем #define private public перед включением заголовочного файла.

KivApple ★★★★★
()

напоминает С в компиляторе из Plan9. ну или Go. ну или Oberon2.

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

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

ещё смотри кроме GObject, COS, например. читай доку с примерами. мультиметоды в стиле

инкапсуляция, наследование, полиморфизм => мультидиспетчеризация и мультифорвардинг сообщений (мультиметоды, то есть, с делегатами (message multidispatch and message multi-forwarding)

вот пример нормально расшияемой объектной системы : в стиле CLOS. и по производительности неплохо, см. тесты.

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

ещё можешь реализацию SOM object model из OS/2 посмотреть. там метаклассы есть, и компоненты с наследованием.

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