суббота, 10 ноября 2012 г.

Методы объекта в C

Когда плюсистов насильно пересаживают на Си, одним из пунктов ломки по нормальным языкам является отсутствие адекватных объектов и их методов. Но если становится совсем плохо, методы можно легко реализовать.

Пусть дана структура, точка, например. Она состоит из 2 координат:

typedef {
    float x;
    float y;
} Point;


Функция изменения координат будет выглядеть так:

void movePointBy(Point * p, int x, int y) {
    p->x += x;
    p->y += y;
}


Но можно применить C++ ситль и тогда у объектов внезапно появятся методы:

typedef struct _Point {
    void (*moveBy) (struct _Point * self, int x, int y);
    float x;
    float y;
} Point;

void movePointBy(Point * p, int x, int y) {
    p->x += x;
    p->y += y;
}

int main() {
    Point p;
    p.moveBy = movePointBy;

    movePointBy(&p, 1, 2);
    p.moveBy(&p, 1, 2);

    return 0;
}


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

Из плюсов у неё только то, что можно меньше заботиться о пространстве имён (часто для решения этой проблемы в Си используется префикс типа point_MoveBy).

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

В общем это приём, который добавляет проблем, не внося никаких плюсов.

UPD: самый существенный минус - осложнения с оптимизацией. Об этом здесь.

6 комментариев:

  1. Когда плюсисты возмущенно говорят о том, что в Си нет объектов - я им показываю GObject из GTK+, Pango и прочих проектов. Всё там есть, и эти ваши объекты :)

    ОтветитьУдалить
    Ответы
    1. Здесь я с плюсистами согласен ) Точнее как... В Си можно эмулировать некое подобие объектов, но не в понимании плюсов. Они скорее к питону ближе.

      На Сишных объектах у тебя не будет ни честных приватных методов, ни конструктора/деструктора. Проблемно сделать полиморфизм. Он либо будет (при этом весьма кривой), но у тебя отвалится и без того никудышная типизация Си, либо сохранияешь типизацию, но на каждый тип пишешь свой отдельный метод.

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

      Удалить
    2. public/privatные методы - это coding sugar, они ж для нас человеков, а не системы существуют :)

      Конструктор/деструктор можно сэмулировать вызовом вручную специальной функции.

      Неявный вызов конструктора - это тоже coding sugar ))

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

      Удалить
    3. Вот, пожалуйте:
      http://maemo.org/api_refs/5.0/beta/gobject/howto-gobject-methods.html

      здесь и
      Non-virtual public methods
      Virtual public methods
      Virtual private Methods

      Удалить
    4. > public/privatные методы - это coding sugar, они ж для нас человеков, а не системы существуют :)

      Ну, плюсовый компилятор ругается, когда пытаешься обратиться к приватным членам из вне. Хотя да, в данном конкретном случае оно действительно больше для человеков.

      Глобально с этой эмуляцией мне не нравятся 2 вещи:
      1 - эмуляция усложняет работу компилятора. Как в плане оптимизаций, так и в плане отслеживания ошибок на стадии написания кода.
      2 - если так люди так упорно пытаются использовать в языке A возможности языка B, то что мешает им сразу взять язык B и не использовать те его возможности, которые не нравятся?

      Удалить
  2. > Из плюсов у неё только то, что можно меньше заботиться о пространстве имён

    Когда я только начал писать на С++ (один из первых моих проектов - 3D движок) я по сути продолжал писать на Си, но оборачивал всё в неймспейсы (namespace). Только потом я прочитал Страуструпа и узнал о том, что основное их назначение - это обёртка и портабельность для старого Сишного кода, во избежании конфликта имён идентификаторов.

    ОтветитьУдалить