LINUX.ORG.RU
ФорумTalks

Почему боятся ООП?

 


0

6

Заметил, что некоторые разрабы стесняются (триггерятся/истерят/брезгуют/отстраняются/впадают_в_кому от) ООП. Почему? Вот, один говорит «у нас тут не наследование, а …», так и хочется добавить «розовые пони». Т.е. если ты можешь реализовывать интерфейсы, у тебя уже нет отношения is-a? Может быть, какие-то древние ЯП не поддерживали чисто виртуальные интерфейсы, и нужен был непременно базовый класс, но как минимум уже C++ сломал эту традицию.

★★★★★
Ответ на: комментарий от monk

я нить потерял. посмотрел что там со строками в Java, оказывается String, StringBuffer, StringBuilder реализуют в том числе и CharSequence - интерфейс представления строки символов. то есть они все совместимы в том отношении, что их содержимое можно брать и читать одинаковым образом.

то есть использующая функция должна иметь параметром CharSequence. и все собссно.

то есть совместимость тут через общий интерфейс, как я в начале говорил.

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

то есть использующая функция должна иметь параметром CharSequence. и все собссно.

Да. Неудачный пример. Тогда пусть будет String, Array и List. Скажем, функция какую-то статистику по элементам коллекции считает. Нужен как бы Iterable, но разработчик в него не включил String.

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

то есть совместимость тут через общий интерфейс, как я в начале говорил.

А в Си++ общих интерфейсов нет ни у строк, ни у массивов, ни у словарей.

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

А в Си++ общих интерфейсов нет ни у строк, ни у массивов, ни у словарей.

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

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

типа пусть нам нужны две функции ff() и fff() для неких неродственных классов a,b,c.

тогда мы рисуем интерфейс

class face0 {
public:
  void ff() = 0;
  void fff() = 0;
}

и реализуем его для a,b,c.

/// for class <a>
class face_a: public face0 {
  a& _ref; ///reference to <a> object 
public:
  face_a(a& fref): _ref(fref) {}
  void ff() override {.... };
  void fff() override {.....};
}

/// for class <b>
...

и тогда наша функция будет иметь заголовок

xxx(face0& fobj)

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

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

xxx(face0& fobj)

Заголовок - понятно.

Вызов

a o = new ...;
xxx(face_a(o));

будет?

С созданием временного объекта? Или Си++ соптимизирует, условно

class face_a: public face0 {
  void ff() override { _ref.ff1(); };
  ...
};

void xxx(face0& fobj)
{
   aaa();
   fobj.ff();
   bbb();
}

xxx(face_a(o));

в

aaa();
o.ff1();
bbb();

?

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

обычно я пишу так:

если надо вызвать только раз ff()

a local_a; ///сам обьект
face_a(local_a).ff(); ///вызов функции ff

а если вызовов много

a local_a; ///сам обьект
face_a face(local_a);

face.ff()
face.fff()
face.ff()
...

вообще face содержит только ссылку на обьект, который он накрывает и адрес таблицы вирт. методов. при оптимизации кода, это скорее всего будет иметь тот же оверхед, что и случай, когда сами классы a,b,c реализуют этот интерейс. как в Java cо строковыми классами.

можно пойти еще дальше и встроить классы a, b, c внутрь реализаций интерфейса face_0, держа там не ссылку, а сам обьект, то есть расширить неродственные классы прямой настройкой реализации интерфейса face_0.

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

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

по поводу оптимизации:

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

и потому никакое тело метода ff он не вставит к вызывающий код. потому что не знает какой вариант ff будет вызван.

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

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

он может и прямо вставить код тела виртуального метода ff. но это частный случай.

Я именно про это. Может ли компилятор в этом случае выкинуть создание/уничтожение класса декоратора? Под RVO вроде не попадает, а если обязательно создаёт уничтожает, то это всё-таки лишние действия по сравнению с хаскелом/лиспом.

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

Я именно про это. Может ли компилятор в этом случае выкинуть создание/уничтожение класса декоратора?

у простого «декоратора» всего два поля - ссылка на сам обьект и адрес VMT. адрес вызываемой функции берется примерно как (* (VMT[fun_index]) ) (_ref).

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

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

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

конструктор не нужен вообще, поскольку _ref на регистре

Вот это и интересовало. Если он может указатель на local_a и _ref оставить в одном регистре, а не выделять _ref на стеке, тогда согласен, что получается не хуже.

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

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

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

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

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

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

И если речь про интовые дескрипторы, это даже не сама сишка, а POSIX.

seiken ★★★★★
() автор топика
Ответ на: комментарий от s-warus

Ограничения на действия делает не ООП, а типизация.

и список их тебе иде подскажет

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

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

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

s-warus ★★★
()
Ответ на: комментарий от seiken

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

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

В си++ операцию << для файла не предлагает. И из pqxx::connection как получить pqxx::work тоже не предлагает.

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

monk ★★★★★
()

Тред не читал. А что плохого в ООП, не пойму? Если это эффективно для поставленной задачи, то почему нет?

Desmond_Hume ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)