Здравствуйте, sergey2b, Вы писали:
R>>Примерно тем же, чем граната в руках человека отличается от гранаты в руках обезяны.
S>мета понятна, S>но можно более формальные критерии
Здравствуйте, sergey2b, Вы писали:
S>Здравствуйте, rg45, Вы писали:
R>>Примерно тем же, чем граната в руках человека отличается от гранаты в руках обезяны.
S>мета понятна, S>но можно более формальные критерии
RAII — это свойство компилятора (при выходе из области видимости, все переменные уничтожаются, в том числе объекты с запуском деструктора). Это позволяет создать, например, ScopeGuard, когда при выходе из области видимости (например, из функции по любой причине) будет выполнен код, переданный этому ScopeGuard при его создании. Таким образом, RAII не может быть ни самописным, ни библиотечным (stl), только компиляторным.
Здравствуйте, Masterspline, Вы писали:
S>>самописный RAII считаеться или только из stl
M>RAII — это свойство компилятора (при выходе из области видимости, все переменные уничтожаются, в том числе объекты с запуском деструктора). Это позволяет создать, например, ScopeGuard, когда при выходе из области видимости (например, из функции по любой причине) будет выполнен код, переданный этому ScopeGuard при его создании. Таким образом, RAII не может быть ни самописным, ни библиотечным (stl), только компиляторным.
в Си при выходе из области видимости переменные тоже уничтожаються
S>как вы считаете чем С++ отличается от Си с классами
Виртуальные функции.
Си с классами не нуждается в виртуальных функциях — отдельные классы можно писать и без них.
Шаблоны, кстати, тоже просто классы, хоть и обобщенные.
А вот открытое наследование с виртуальными функциями — это дао ООП.
Динамический полиморфизм (так сказал Александреску).
Пока вы не постигнете виртуальность — вы не постигнете ООП.
И принцип подстановки — единственный из принципов SOLID, реализованный непосредственно в языках программирования.
Остальные принципы — это благие пожелания...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, sergey2b, Вы писали:
S>как вы считаете чем С++ отличаеться от Си с классами
Если без полутонов, то ответ в вопросе — оборачиваем код на голом C в классы и получаем конструктор, деструктор и отсутствие необходимости передавать хэндл объекта в каждую функцию
Здравствуйте, sergey2b, Вы писали:
S>в Си при выходе из области видимости переменные тоже уничтожаються
...память под которые выделенна в стеке. С++ позволяет красиво использовать это для освобождения любых ресурсов.
Здравствуйте, LaptevVV, Вы писали:
LVV>И принцип подстановки — единственный из принципов SOLID, реализованный непосредственно в языках программирования.
Можно поподробнее? Или ссылку подтверждающую.
Здравствуйте, sergey2b, Вы писали:
S>как вы считаете чем С++ отличаеться от Си с классами
Я бы провёл границу по наличию/отсутствию compile time execution. Это единственное, чего нельзя реализовать в чистом Cи. Си с классами-это есть расширенный Cи. И неважно, расширен ли он на уровне компилятора (все эти RAII, exceptions, etc) или на уровне некоторого Cи-шного фреймворка, которые предоставляет нужные функции в виде макросов, структур, процедур etc.
Здравствуйте, smeeld, Вы писали:
S>Это уже перетёрто сто раз на данном форуме.
пока выше ответившие разделились вомнении
вопрос возник потому что я пришел на собеседование
рассказал, чем я занимался, а мне говорят ты писал на Си с классами, мы поспорили 5 минут и собеседование закончилось
Здравствуйте, sergey2b, Вы писали:
S>вопрос возник потому что я пришел на собеседование S>рассказал, чем я занимался, а мне говорят ты писал на Си с классами, мы поспорили 5 минут и собеседование закончилось
S>вот решил сверить понимание вопроса
"Дизайн и эволюцию" не читал, поэтому попытаюсь сформулировать по-своему.
Есть типично Сишные приемы работы, а есть "Приплюснутые"
Скажем, run-time полиморфизм реализуем и там, и там. Но через указатели на функции — Сишная фишка, а виртуальные функции — С++.
Завязка на RAII (сюда можно отнести и использование к-торов/д-торов) — С++ приём, недостижимый в Си. В Си приходится отделять этапы получения и освобождения ресурсов от их использования.
Исключения. Завязка на исключения — это С++, применение кодов возврата — Си, либо Си с классами.
Шаблоны.
С одной стороны использование шаблонного std::vector не превращает код из "Си с классами" в С++. Зато лямбды и оптимизация шаблонного кода могут дать код гораздо эфективнее, чем аналог на Си. Т.е. можно считать, что активное применение compile-time полиморфизма, вычислений, кодогенерации делают код явно плюсатым.
Ну вот так как-то...
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, sergey2b, Вы писали:
S>как вы считаете чем С++ отличаеться от Си с классами
C++ это
Повсеместное использование RAII
Использование возможностей системы типов для сокращение возможных ошибок в коде
Использование стандартной библиотеки: контейнеры, алгоритмы, smart pointers, threads, примитивы синхронизации, bind, function, limits, streams
Использование исключений
Шаблоны, variadic шаблоны, хотя бы базовое понимание принципов шаблонного метапрограммирование, SFINAE, type_traits, enable_if
Move семантика
ООП
Перегрузка функций и операторов
Использование boost'а
А также ясное понимание зачем все вышеперечисленное нужно и как оно работает, в том числе и понимание того, когда данные средства могут не подойти и их лучше избегать.
LVV>>И принцип подстановки — единственный из принципов SOLID, реализованный непосредственно в языках программирования. МР>Можно поподробнее? Или ссылку подтверждающую.
В гугле забанили?
Есть десятки ссылок (вики, хабр...)
Автором считается Боб Мартин — он во всех своих книжках прописывает эти 5 (пять) принципов.
С подробными разъяснениями.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>>>И принцип подстановки — единственный из принципов SOLID, реализованный непосредственно в языках программирования. МР>>Можно поподробнее? Или ссылку подтверждающую.
LVV>Автором считается Боб Мартин — он во всех своих книжках прописывает эти 5 (пять) принципов. LVV>С подробными разъяснениями.
Не, Валерий Викторович, про SOLID в целом понятно.
Но мне вот тоже любопытно послушать про "принцип подстановки, реализованный непосредственно в языках программирования".
Я вот, наоборот, регулярно встречаю нарушение LSP в любых языках программирования. И не вижу, как язык программирования может как-то обеспечить его соблюдение.
_____________________
С уважением,
Stanislav V. Zudin
SVZ>Не, Валерий Викторович, про SOLID в целом понятно. SVZ>Но мне вот тоже любопытно послушать про "принцип подстановки, реализованный непосредственно в языках программирования". SVZ>Я вот, наоборот, регулярно встречаю нарушение LSP в любых языках программирования. И не вижу, как язык программирования может как-то обеспечить его соблюдение.
Не понял.
В любом языке открытое наследование означает, что на место объекта (указателя, ссылки) МОЖЕТ быть подставлен объект (указатель, ссылка) производного типа.
Обратное — неверно.
Любой будильник (производный тип) является часами (базовый тип), но обратное — неверно.
И это — РЕАЛИЗОВАНО в ЛЮБОМ языке.
Какие еще требуются объяснения?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
SVZ>>Не, Валерий Викторович, про SOLID в целом понятно. SVZ>>Но мне вот тоже любопытно послушать про "принцип подстановки, реализованный непосредственно в языках программирования". SVZ>>Я вот, наоборот, регулярно встречаю нарушение LSP в любых языках программирования. И не вижу, как язык программирования может как-то обеспечить его соблюдение. LVV>Не понял. LVV>В любом языке открытое наследование означает, что на место объекта (указателя, ссылки) МОЖЕТ быть подставлен объект (указатель, ссылка) производного типа. LVV>Обратное — неверно. LVV>Любой будильник (производный тип) является часами (базовый тип), но обратное — неверно. LVV>И это — РЕАЛИЗОВАНО в ЛЮБОМ языке.
Семёёён Семёныч...
Наследование интерфейса же не гарантирует соблюдение LSP.
Каноничный пример: квадрат является прямоугольником, но наследование объекта Square от интерфейса IRectangle является нарушением LSP.
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, sergey2b, Вы писали:
S>вопрос возник потому что я пришел на собеседование S>рассказал, чем я занимался, а мне говорят ты писал на Си с классами, мы поспорили 5 минут и собеседование закончилось
ИМХО, тебе не стоит воспринимать этот ответ столь буквально. Главный вывод, который тебе следовало бы сделать, это то, что тебе нужно подтягивать свой уровень владения C++. А выражено это могло быть в множестве самых разнообразных форм.
SVZ>Семёёён Семёныч... SVZ>Наследование интерфейса же не гарантирует соблюдение LSP. SVZ>Каноничный пример: квадрат является прямоугольником, но наследование объекта Square от интерфейса IRectangle является нарушением LSP.
Мы говорим о классах!
И реализация интерфейса в виде абстрактного класса в С++ — таки обеспечивает LSP.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
SVZ>>Наследование интерфейса же не гарантирует соблюдение LSP. SVZ>>Каноничный пример: квадрат является прямоугольником, но наследование объекта Square от интерфейса IRectangle является нарушением LSP. LVV>Мы говорим о классах!
ОК, пусть будут классы.
LVV>И реализация интерфейса в виде абстрактного класса в С++ — таки обеспечивает LSP.
Интерфейсы, абстрактные классы (обзови как угодно), так сказать, предоставляют средства, но не дают 100% гарантию.
Пример с квадратом тому подтверждение.
Соблюдение LSP полностью оказывается на совести проектировщика.
Мало реализовать интерфейс, "...поведение наследуемых классов не должно противоречить поведению, заданному базовым классом, то есть поведение наследуемых классов должно быть ожидаемым для кода, использующего переменную базового типа..." (с)Вики
Да, раз уж упомянули дядю Боба, то из его же статьи: The Circle/Ellipse Dilemma. Читаем про "Clients Ruin Everything" и рыдаем.
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, sergey2b, Вы писали:
S>как вы считаете чем С++ отличаеться от Си с классами
У всех тут, безусловно, будет свое видение, но я бы отметил следующие наиболее критические моменты (я пишу про некий обобщенный случай, так как иногда и свои контейнеры более чем оправданны, и макросы нужны и т.д.):
Использованием ручного управления памятью против автоматического;
Игнорированием RAII в общем случае с ручным заходом солнца;
Использованием макросов вместо шаблонов;
Написанием своих алгоритмов/контейнеров вместо использования STL;
Адресной арифметикой вместо итераторов и алгоритмов;
Как мне кажется, когда говорят что "код выглядит как Си-с-классами" обычно хотят сказать "код выглядит как говно мамонта", но стесняются
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Семёёён Семёныч... SVZ>Наследование интерфейса же не гарантирует соблюдение LSP. SVZ>Каноничный пример: квадрат является прямоугольником, но наследование объекта Square от интерфейса IRectangle является нарушением LSP.
Насколько я понимаю, то, что квадрат нельзя наследовать от прямоугольника не является следствием LSP. Такое наследование нарушает какой-то другой принцип, но не нарушает принципа подстановки Барбары Лисков.
Какое из свойств прямоугольника на выполняется для квадрата? Можете указать?
Здравствуйте, B0FEE664, Вы писали:
SVZ>>Каноничный пример: квадрат является прямоугольником, но наследование объекта Square от интерфейса IRectangle является нарушением LSP.
BFE>Насколько я понимаю, то, что квадрат нельзя наследовать от прямоугольника не является следствием LSP. Такое наследование нарушает какой-то другой принцип, но не нарушает принципа подстановки Барбары Лисков. BFE>Какое из свойств прямоугольника на выполняется для квадрата? Можете указать?
Тут ниже я привел ссылку на статью Р. Мартина, где тот разбирает ту же проблему, но с кругом и эллипсом.
В самом наследовании проблемы нет, но есть в использовании.
Т.е. если кто-то ожидает от интерфейса IRectangle, что при смене ширины высота не изменится, то с квадратом его ждёт разочарование.
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Тут ниже я привел ссылку на статью Р. Мартина, где тот разбирает ту же проблему, но с кругом и эллипсом. SVZ>В самом наследовании проблемы нет, но есть в использовании.
SVZ>Т.е. если кто-то ожидает от интерфейса IRectangle, что при смене ширины высота не изменится, то с квадратом его ждёт разочарование.
Поэтому, как мне кажется, самым разумным шагом является отказ от наследования как такового. В этом случае остаются только интерфейсы без возможности наследования, но желательно с возможностью агрегации и LSP реализуется и контролируется компилятором в разы проще.
Здравствуйте, Stanislav V. Zudin, Вы писали:
BFE>>Какое из свойств прямоугольника на выполняется для квадрата? Можете указать?
SVZ>Тут ниже я привел ссылку на статью Р. Мартина, где тот разбирает ту же проблему, но с кругом и эллипсом. SVZ>В самом наследовании проблемы нет, но есть в использовании. SVZ>Т.е. если кто-то ожидает от интерфейса IRectangle, что при смене ширины высота не изменится, то с квадратом его ждёт разочарование.
Да, я согласен, что так делать нельзя и будут разочарования, но нарушения LSP я тут не вижу. В статье Р. Мартина говорится, что круг якобы не может реализовать контракт эллипса. Но фактически это не так, потому, что контракт выраженный в виде интерфейса подменяется другим контрактом — соблюдением постусловий, которые в самом контракте (== интерфейсе) никак не выражены.
Фактически, не верен код использования, а не контракта:
void f(Ellipse& e)
{
Point a(-1,0);
Point b(1,0);
e.SetFoci(a,b);
e.SetMajorAxis(3);
assert(e.GetFocusA() == a);
assert(e.GetFocusB() == b);
assert(e.GetMajorAxis() == 3);
}
SVZ>Интерфейсы, абстрактные классы (обзови как угодно), так сказать, предоставляют средства, но не дают 100% гарантию. SVZ>Пример с квадратом тому подтверждение. SVZ>Соблюдение LSP полностью оказывается на совести проектировщика. SVZ>Мало реализовать интерфейс, "...поведение наследуемых классов не должно противоречить поведению, заданному базовым классом, то есть поведение наследуемых классов должно быть ожидаемым для кода, использующего переменную базового типа..." (с)Вики
Вики — такая Вики... Читайте классиков: Тимоти Бадд. ООП в действии.
Наследование может применяться в самых разнообразных смыслах (и по-разному быть реализованным). Например: 1 Специализация. Класс-наследник является специализированной формой родительского класса — в наследнике просто переопределяются методы. Принцип подстановки выполняется. Очевидно, что такая форма наследования в С++ реализуется простым открытым наследованием. Примером является наследование часы * будильник.
2 Спецификация. Дочерний класс реализует поведение, описанное в родительском классе. Ясно, что в С++ эта форма реализуется простым открытым наследованием от абстрактного класса.
3 Конструирование. Класс-наследник использует методы базового класса, но не является его подтипом (принцип подстановки не выполняется). В С++ такую форму можно реализовать простым закрытым наследованием.
4 Расширение. В класс-потомок добавляют новые методы, расширяя поведение родительского класса; принцип подстановки в такой форме выполняется.
5 Обобщение. Дочерний класс обобщает поведение базового класса. Обычно такое наследование требуется в тех случаях, когда мы не можем изменить поведение базового класса (например, базовый класс является библиотечным).
6 Ограничение. Класс-наследник ограничивает поведение родительского класса. Очевидно, что в С++ такой вид наследования реализуется простым закрытым наследованием (пример — TDeque -> TStack).
7 Варьирование. Базовый и производный классы являются вариациями на одну тему, однако связь «класс-подкласс» произвольна, например, «квадрат-прямоугольник» или «прямоугольник-квадрат». Эта форма фактически не отличается от «конструирования», так как класс-наследник, очевидно, «использует методы базового класса, но не является его подтипом».
8 Комбинирование. Дочерний класс наследует черты нескольких классов — это множественное наследование
Так что все зависит от контекста. SVZ>Да, раз уж упомянули дядю Боба, то из его же статьи: The Circle/Ellipse Dilemma. Читаем про "Clients Ruin Everything" и рыдаем.
Есть пример и поближе.
Чистая архитектура, например.
Но он описывает не отсутствие реализации принципа подстановки, а неправильную архитектуру.
Принцип подстановки был и остается реализованным при открытом наследовании.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Автором считается Боб Мартин — он во всех своих книжках прописывает эти 5 (пять) принципов.
А я не про пять принципов спрашивал, а про то откуда вы взяли что принцип подстановки реализован непосредственно в языках программирования
Здравствуйте, LaptevVV, Вы писали:
LVV>Принцип подстановки был и остается реализованным при открытом наследовании.
Ну все таки можете привести цитату или статью подтверждающую, это?
LVV>>Принцип подстановки был и остается реализованным при открытом наследовании. МР>Ну все таки можете привести цитату или статью подтверждающую, это?
Какая вам цитата нужна, если в С++ принцип подстановки реализован?
И в Додиезе, И в Яве, и в Компонентном паскале...
Вот вам цитата из меня:
Открытое наследование устанавливает между классами отношение «является»: класс-наследник является разновидностью класса-родителя. И это не просто словесная формулировка — она непосредственно поддерживается компилятором. Когда мы пишем, что класс Derived (производный) открыто наследует от класса Base (базовый), мы сообщаем компилятору, что каждый объект типа Derived является также объектом класса Base. С практической точки зрения это означает, что везде, где может быть использован объект типа Base, вместо него разрешается подставлять объект типа Derived — это и есть принцип подстановки. Этот принцип работает и для ссылок, и для указателей: вместо ссылки (указателя) на базовый класс может быть подставлена ссылка (указатель) на класс-наследник. Преобразование типа при этом указывать не требуется не обязательно — оно выполняется автоматически. В [11] такое приведение типов названо повышающим.
11. Эккель Б. Философия С++. Введение в стандартный С++. 2-е изд. — СПб.: Питер, 2004.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Какая вам цитата нужна, если в С++ принцип подстановки реализован?
Принцип подстановки Барбары Лисков про выполнение инвариантов контракта интерфейса, про пред и пост условия, а не про просто возможность подстановки наследника вместо родителя.
Здравствуйте, LaptevVV, Вы писали:
LVV>>>Принцип подстановки был и остается реализованным при открытом наследовании. МР>>Ну все таки можете привести цитату или статью подтверждающую, это? LVV>Какая вам цитата нужна, если в С++ принцип подстановки реализован?
А вы знаете что такое принцип подстановки Барбары Лисков? Может быть стоит ознакомиться?
LVV>>>>Принцип подстановки был и остается реализованным при открытом наследовании. МР>>>Ну все таки можете привести цитату или статью подтверждающую, это? LVV>>Какая вам цитата нужна, если в С++ принцип подстановки реализован? МР>А вы знаете что такое принцип подстановки Барбары Лисков? Может быть стоит ознакомиться?
Знакомьтесь.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
LVV>>Какая вам цитата нужна, если в С++ принцип подстановки реализован? V>Принцип подстановки Барбары Лисков про выполнение инвариантов контракта интерфейса, про пред и пост условия, а не про просто возможность подстановки наследника вместо родителя.
Таким образом, идея Лисков о «подтипе» даёт определение понятия замещения — если S является подтипом T, тогда объекты типа T в программе могут быть замещены объектами типа S без каких-либо изменений желательных свойств этой программы
Что в практическом программировании повсеместно и используется.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Таким образом, идея Лисков о «подтипе» даёт определение понятия замещения — если S является подтипом T, тогда объекты типа T в программе могут быть замещены объектами типа S
без каких-либо изменений желательных свойств этой программы
Таким образом, идея Лисков о «подтипе» даёт определение понятия замещения — если S является подтипом T, тогда объекты типа T в программе могут быть замещены объектами типа S
V>
без каких-либо изменений желательных свойств этой программы
V>
V>
Что такое: "желательные свойства программы"? Если, например, ромбы сделать подтипом эллипсов и заменить все эллипсы на ромбы — это будет изменением "желательных свойств программы" или нет?
Здравствуйте, B0FEE664, Вы писали:
BFE>Что такое: "желательные свойства программы"? Если, например, ромбы сделать подтипом эллипсов и заменить все эллипсы на ромбы — это будет изменением "желательных свойств программы" или нет?
У разработчика программы надо спросить В том же наследовании квадрата от прямоугольника ( и наоборот ) нет ранее описанной проблемы в случае, если в контракте нет методов изменяющих величины сторон
Здравствуйте, LaptevVV, Вы писали:
S>>как вы считаете чем С++ отличается от Си с классами LVV>Виртуальные функции. LVV>Си с классами не нуждается в виртуальных функциях — отдельные классы можно писать и без них.
Не как раз в C с классами виртуальные функции очень полезны.
Они позволяют удобно писать модули
Здравствуйте, sergey2b, Вы писали:
S>как вы считаете чем С++ отличаеться от Си с классами
В кратце: в с++ можно себе с комфортом, после грячей ванны, под чафечку кофэ и пластинку классической музыки, себе ноги прострелить. Причём пуля классически войдёт через ооп'у.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, LaptevVV, Вы писали:
LVV>Любой будильник (производный тип) является часами (базовый тип), но обратное — неверно. LVV>И это — РЕАЛИЗОВАНО в ЛЮБОМ языке.
Веселье в том, что будильник совершенно не обязан быть часами. Более того, он чаще всего является чем угодно, но не часами.
И вот на такой мелочи огромное число самодельных ООП архитектур конкретно так обделываются. Безотносительно языка программирования.
L>Веселье в том, что будильник совершенно не обязан быть часами. Более того, он чаще всего является чем угодно, но не часами. L>И вот на такой мелочи огромное число самодельных ООП архитектур конкретно так обделываются. Безотносительно языка программирования.
Можно и отдельно.
Зависит от задачи и предметной области.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Vain, Вы писали:
V>В кратце: в с++ можно себе с комфортом, после грячей ванны, под чафечку кофэ и пластинку классической музыки, себе ноги прострелить. Причём пуля классически войдёт через ооп'у.
Здравствуйте, LaptevVV, Вы писали:
L>>И вот на такой мелочи огромное число самодельных ООП архитектур конкретно так обделываются. Безотносительно языка программирования. LVV>Можно и отдельно. LVV>Зависит от задачи и предметной области.
На самом деле практически не зависит. Будильник применительно к программированию — это сигнал. Наследовать будильник от часов означает заранее налагать определенные ограничения и требования как на поставщика этого сигнала, так и на подписчика.
Только и всего.
Здравствуйте, YuriV, Вы писали:
V>>В кратце: в с++ можно себе с комфортом, после грячей ванны, под чафечку кофэ и пластинку классической музыки, себе ноги прострелить. Причём пуля классически войдёт через ооп'у. YV>Стэндапер?
Стендап прогер
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]