Название: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 16, 2014, 08:14 Привет!
Расскажите о своём подходе к созданию ООП программ. С чего вы начинаете разработку? Какими инструментами пользуетесь для построения диаграмм? В каких случаях используете виртуальные функции и полиморфизм? Если все используют UML, то подскажите: где скачать? как использовать? И дайте, пожалуйста, ссылку на простой и доступный туториал :) Допустим мне нужно создать игру. Как определиться с требованиями? Как построить архитектуру? Пусть она будет текстовая-консольная (у меня нет сил осваивать OpenGL) За основу я возьму проект из каталога examples/json/savegame Там следующие классы: game.h Код
character.h Код
level.h Код
main.cpp Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 16, 2014, 08:28 Если вы по настоящему хотите с этим разобраться, то эту книгу нужно почитать обязательно:
Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 16, 2014, 10:01 Спасибо большое! Начал изучать.
Почитал на ozon.ru отзывы: http://www.ozon.ru/context/detail/id/3905587/#tab_comments Все ругают русский перевод. Говорят, что нужно обязательно иметь под рукой оригинал. К счастью, я английский хорошо понимаю. Буду читать на русском и заглядывать в оригинал. Перевод: http://rutracker.org/forum/viewtopic.php?t=3343958 Оригинал: http://kickass.to/object-oriented-analysis-and-design-with-applications-3rd-editio-t2753820.html Прилагаются ли к книге какие-нибудь дополнительные материалы (например, исходники или\и файлы UML)? Обычно исходники в отдельную папку помещают и их можно откуда-нибудь скачать. Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 16, 2014, 10:05 Прилагаются ли к книге какие-нибудь дополнительные материалы (например, исходники или\и файлы UML)? Нет. Это фундаментальный труд, компилируемых примеров в нем нет. Зато на примерах разбирается как же нужно думать, что бы проектировать ОО-программы.Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 16, 2014, 11:56 Расскажите о своём подходе к созданию ООП программ. С чего вы начинаете разработку? Какими инструментами пользуетесь для построения диаграмм? В каких случаях используете виртуальные функции и полиморфизм? - Не думаю что надо разделять программы на "ООП и нет". - Диаграммы - не знаю точно что Вы имеете ввиду. Часто использую гистограммы (обычно просто печать в консоли), иногда графики. А чаще всего сливаю линии/точки (иногда раскрашенные) в текстовик и визуализирую это в 3D. - виртуалы и.т.п. Все это цветет пышным цветом в UI, в расчетной части иерархия классов может быть очень небольшой и "конкретные" классы могут доминировать. Зато часто нужен гораздо более тщательный выбор структур данных и контейнеров. С чего начинать разработку. С четкого понимания "кому это нужно". Можно сказать и "кому это можно продать" - не вижу в этом ничего плохого. Пройдет какое-то время и любой энтузиазм угаснет, это нормально, запас энергии человека ограничен. Поэтому надо прикинуть - а что я успею сделать "на первой волне", пока мне (еще) интересно этим заниматься. Сумею ли достичь каких-то пусть промежуточных но реальных результатов? Потому что неоплачиваемый проект долго не протянет. А учитывая еще что Вы делаете массу др дел .. :) В общем до пресловутой "архитектуры" еще очень далеко. Сначала ТЕМУ/задачу выберите тщательно, пока у меня впечатление что для Вас это дело десятое, типа "что угодно лишь бы опыта набраться". Это не вредно, но и пользы не много. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 17, 2014, 15:40 Диаграммы - не знаю точно что Вы имеете ввиду. Часто использую гистограммы (обычно просто печать в консоли), иногда графики. А чаще всего сливаю линии/точки (иногда раскрашенные) в текстовик и визуализирую это в 3D. Я имею ввиду диаграммы наследования. А Вы? виртуалы и.т.п. Все это цветет пышным цветом в UI А на примере проекта "savegame" (о котором я написал вначале) можно же поиграть с наследованием, полиморфизмом, виртуальными функциями? Как мне развивать этот проект (консольная игра), чтобы я видел, что мне действительно улучшает жизнь полиморфизм (и т.д.)? Я хочу на этом живом примере применить ООП в полной мере! Мне нужны идеи именно по этому проекту. Я думаю, что разработка простой игры - это как раз то, что нужно для тренировки ООП. Но у меня в этом проекте полный тупик. Я буду рад любым идеям по его развитию (с точки зрения применения всех аспектов ООП). Вот тут создаётся этот персонаж (за которого мы будем играть). Как мне заставить его ходить? Создаётся так же несколько неигровых персонажей (NPS) на разных локациях (этот пример расположен в папке Qt examples/json/savegame): Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 17, 2014, 16:59 Я имею ввиду диаграммы наследования. А Вы? Если они есть в ID - иногда смотрю (редко). А нет - прекрасно обхожусь без них. А на примере проекта "savegame" (о котором я написал вначале) можно же поиграть с наследованием, полиморфизмом, виртуальными функциями? Как мне развивать этот проект (консольная игра), чтобы я видел, что мне действительно улучшает жизнь полиморфизм (и т.д.)? Я хочу на этом живом примере применить ООП в полной мере! Мне нужны идеи именно по этому проекту. Я думаю, что разработка простой игры - это как раз то, что нужно для тренировки ООП. Я так не думаю. Фрагмент кода что Вы показали - это уже манипуляции "верхнего уровня", когда все готово/выписано и этим надо рулить. ООП здесь ни при чем. Конечно можно поиграться с этим примером - но на этом дело и кончится.Вообще примеры - палка о двух концах. Создается впечатление что все довольно "просто" и даже "элементарно" - но смогли бы Вы сделать все это "с нуля"? Да, Вы узнаете много нового, но также и "попадаете под влияние" могучих троллей, и в этом есть свои минусы. Вот относительно недавно тут паренек писал свой морской бой с нуля - мне кажется такой подход лучше. Задумка должна быть своя, а идей "простой" игры предостаточно Возвращаясь к ООП - вряд ли игровой проект может служить для его тренировки. Есть пример ООП наследования который приводится с незапамятных времен: фигуры. Напр есть базовый класс Shape, от него наследуется Circle, Triangle и.т.п. Аналогичный пример есть в Qt (кажется демонстрация undo, точно не помню). Хоть и не игра - но для освоения ООП подойдет гораздо лучше Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 17, 2014, 17:20 Возвращаясь к ООП - вряд ли игровой проект может служить для его тренировки. Конечно может и очень хорошей. А написание своего рогалика, так вообще замечательная идея.В нем очень много объектов разных классов, которые должны взаимодействовать друг с другом. А пример с фигурами... Это для детского сада. Название: Re: Как писать ООП программы? Отправлено: Bepec от Февраль 17, 2014, 17:34 На мой взгляд только игра и способствует развитию ООП мышления. Ибо в играх обычно приводится реальный мир с его разнообразием объектов. Всё под рукой :)
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 17, 2014, 18:19 А пример с фигурами... Это для детского сада. Смотря как к нему подходить. С чем-то более сложным - боюсь все уйдет в изучение того что уже сделано (готовых классов), и на изобретение чего-то своего ничего не останетсяА вот кстати сегодняшний пример наследования http://www.prog.org.ru/index.php?topic=26553.msg190549#msg190549 (http://www.prog.org.ru/index.php?topic=26553.msg190549#msg190549) Что Вы о нем думаете? Old, просьба не спешить, пусть сначала товарищи выскажутся :) Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 17, 2014, 18:25 С чем-то более сложным - боюсь все уйдет в изучение того что уже сделано (готовых классов), и на изобретение чего-то своего ничего не останется А в своем рогалике нет готовых классов, там все нужно делать с нуля. Вообще все. :)Нечего изучать, можно только делать. А текстовый интерфейс не дает уйти в создание красивых эффектов вместо хорошего геймплея. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 18, 2014, 15:26 Всем большое спасибо! Начну с простого.
Поступим следующим образом: я буду писать классы, а вы их критикуйте. Задача у меня - довести каждый класс до уровня профи. Классы будут демонстрировать один или несколько принципов ООП. Подкидывайте, пожалуйста, идеи - какие принципы и на каких классах ещё можно рассмотреть. Примеры будут на Qt и на C++, чтобы меня не ругали, что это форум Qt, а не C++. Рациональные числа Примечание. Пример взял отсюда: http://www.e-reading.co.uk/chapter.php/1002058/56/Mayers_-_Effektivnoe_ispolzovanie_CPP.html В примере затронуты следующие темы: - список инициализации в конструкторе - дружественные функции - перезагрузка операторов: умножения, сложения и вычитания. Какие ещё операторы посоветуете перезагрузить? Как дальше доработать этот класс? Примечание. При сложении и вычитании дробей: к общему знаменателю привожу - перемножением, результат не сокращаю. Вывод: product = 6/24 sum = 1472/768 sub = 32/768 main.cpp Код
rational.h Код
rational.cpp Код
Название: Re: Как писать ООП программы? Отправлено: Bepec от Февраль 18, 2014, 15:54 Походу все темы можно в говорилку отправлять :D
PS я не имею в виду, что они флуд. Но к вопросам они явно не относятся :D Название: Re: Как писать ООП программы? Отправлено: m_ax от Февраль 18, 2014, 15:58 Цитировать Примечание. При сложении и вычитании дробей: к общему знаменателю привожу - перемножением, результат не сокращаю. Это плохо( Во-вторых, хотелось бы иметь операторы сравнения.. И такие, чтобы, например, 4/2 и 10/5 получались равными друг другу) И ещё я бы посмотрел на Compile-time rational arithmetic http://en.cppreference.com/w/cpp/numeric/ratio (http://en.cppreference.com/w/cpp/numeric/ratio) Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 18, 2014, 16:08 Примеры будут на Qt и на C++, чтобы меня не ругали, что это форум Qt, а не C++. Ну так Вас забросают помидорами, скажут что "занимаетесь фигней" - и, в общем, это будет правильно :). Вы бросились в др крайность - слишком просто, нет достойного обсуждения предмета. "Отдельно стоящий класс" можно разрисовать как угодно красиво, но столь же бесполезно - потому что нет никаких связок/взаимодействий классов. Подкинуть идей - ну так, наскидку, трудновато. Впрочем один я уже подкинул (с тенью окна, см выше). Хорошо, вот еще - в классическом примере с фигурами утверждается что "каждая фигура умеет себя рисовать", это полиморфный метод. Какие недостатки у такого решения? Так ли уж оно бесспорно? Можно ли привести пример когда оно оказывается неудачным? Название: Re: Как писать ООП программы? Отправлено: deMax от Февраль 19, 2014, 07:30 Цитировать Если все используют UML, то подскажите: где скачать? как использовать? И дайте, пожалуйста, ссылку на простой и доступный туториал Улыбающийся А кто то этой штукой пользуется?http://habrahabr.ru/post/153353/ Цитировать Используете ли вы UML? 3%(122) Пользуюсь постоянно (очень нужный инструмент) 18%(664) Иногда бывает полезен 0%(17) К сожалению, довольно часто приходится пользоваться 6%(234) Приходится пользоваться, но слава богу - не часто 55%(2039) Не пользуюсь 18%(661) Не пользуюсь, но подумываю Название: Re: Как писать ООП программы? Отправлено: Akon от Февраль 19, 2014, 09:33 8Observer8: Не тратьте время на бесполезные примеры, их развитие и т.п. Беритесь сразу за реальную (полезную) задачу. Применить ООП можно и в ней. Когда вы реализуете то, что изначально у вас в голове, вы находитесь на более глубоком уровне понимания и ООП реализацию увидеть будет легче.
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 19, 2014, 10:01 8Observer8: Не тратьте время на бесполезные примеры, их развитие и т.п. Беритесь сразу за реальную (полезную) задачу. Применить ООП можно и в ней. Когда вы реализуете то, что изначально у вас в голове, вы находитесь на более глубоком уровне понимания и ООП реализацию увидеть будет легче. Спасибо за совет! Я не так уж и много трачу времени на примеры. Просто мне так легче понимать отдельные принципы ООП. "Полезную" задачу очень трудно придумать, так как уже почти всё реализовано другими программистами. А кто то этой штукой пользуется? Я так понимаю, что удобнее всего использовать программу doxygen, так как она генерирует и диаграммы наследования. Примером может служить документация для Qwt: http://qwt.sourceforge.net/class_qwt_plot.html (http://qwt.sourceforge.net/class_qwt_plot.html) Подкинуть идей - ну так, наскидку, трудновато. Впрочем один я уже подкинул (с тенью окна, см выше). Хорошо, вот еще - в классическом примере с фигурами утверждается что "каждая фигура умеет себя рисовать", это полиморфный метод. Какие недостатки у такого решения? Так ли уж оно бесспорно? Можно ли привести пример когда оно оказывается неудачным? Igors, Спасибо! Я помню про тот пример. Вернусь к нему позже. Спасибо за новый! Хороший пример. Как раз то, что нужно. Но пока не готов ответить. Цитировать Примечание. При сложении и вычитании дробей: к общему знаменателю привожу - перемножением, результат не сокращаю. Это плохо( Во-вторых, хотелось бы иметь операторы сравнения.. И такие, чтобы, например, 4/2 и 10/5 получались равными друг другу) И ещё я бы посмотрел на Compile-time rational arithmetic http://en.cppreference.com/w/cpp/numeric/ratio (http://en.cppreference.com/w/cpp/numeric/ratio) Да, Вы правы! Но мне не хочется замарачиваться с сокращениями дробей и поиском наименьшего общего знаменателя. Время дорого. Тут главное ООП освоить. После прочтения вот этого правила, у меня возникли сложности с пониманием: Правило 23: Предпочитайте функциям-членам функции, не являющиеся ни членами, ни друзьями класса http://www.e-reading.co.uk/chapter.php/1002058/60/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Получается, что оператор вывода на экран (<<) НЕ должен быть частью класса Relation, так как это НЕ свойство чисел (вывод на экран не относится к классу Relation, так как с точки зрения математики у рациональных чисел есть только свойства сложения, сравнения и т.д.). Следуя правилу, оператор вывода нужно располагать отдельно от класса Relation и даже не friend, а отдельной функцией. Но в том же пространстве имён. А можно ли так делать? C++ позволяет ли создавать свободные операторные функции? Под свободными функциями имеются ввиду функции, которые не являются ни членами-функциями класса, ни функциями-друзьями. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 19, 2014, 10:54 Получается, что оператор вывода на экран (<<) НЕ должен быть частью класса Relation, так как это НЕ свойство чисел (вывод на экран не относится к классу Relation, так как с точки зрения математики у рациональных чисел есть только свойства сложения, сравнения и т.д.). Следуя правилу, оператор вывода нужно располагать отдельно от класса Relation и даже не friend, а отдельной функцией. Но в том же пространстве имён. А можно ли так делать? C++ позволяет ли создавать свободные операторные функции? Под свободными функциями имеются ввиду функции, которые не являются ни членами-функциями класса, ни функциями-друзьями. Можно ли (и как) - откройте какой-нибудь простенький Qt класс (напр QRect) и там посмотрите синтаксис. Форум с таким вопросом беспокоить не стоит.А так Вы столкнулись с типичным "каноническим" правилом - которое часто доводится до абсурда. Ах, якобы это уже НЕ свойство чисел - да неужели? Кто как не сам класс знает как себя печатать? В действительности же дело в другом. Пример Код Беда в том что теперь класс Rational уже не сможет жить без std::ofstream, создается "плохая" зависимость классов. Однако никто не мешает написать так Код Но сила "канона" велика, все-таки с ним лучше/практичнее не спорить :) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 20, 2014, 07:07 Igors, Спасибо большое!
Можно ли (и как) - откройте какой-нибудь простенький Qt класс (напр QRect) и там посмотрите синтаксис. Форум с таким вопросом беспокоить не стоит. Вопрос же был такой: C++ позволяет ли создавать свободные операторные функции? Гугл молчит. Беда в том что теперь класс Rational уже не сможет жить без std::ofstream, создается "плохая" зависимость классов. Чем плоха эта зависимость? Мы тоже при программировании консольных приложений не можем жить без <iostream> И ещё вопрос. Как оператор в моём случае написать? Ошибка: main.cpp:15: error: no match for 'operator<<' (operand types are 'QTextStream' and 'Rational') cout << "product = " << product << endl; ^ Код: #include <QCoreApplication> Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 20, 2014, 07:15 Вопрос же был такой: Что же вы так, а поговорить... :)C++ позволяет ли создавать свободные операторные функции? Гугл молчит. А почему нет, конечно позволяет.Дружба нужна, только если нужен доступ к закрытым членам. Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 20, 2014, 07:20 Вопрос же был такой: C++ позволяет ли создавать свободные операторные функции? Гугл молчит. можно: Код: class Bar P.S. пока писал, ответили Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 20, 2014, 08:24 Чем плоха эта зависимость? Мы тоже при программировании консольных приложений не можем жить без <iostream> Цитата: Гради Буч Наименее желательной является связность по случайному принципу, когда в одном классе или модуле собираются совершенно независимые абстракции. Для примера можно вообразить класс, соединяющий абстракции собак и космических аппаратов. Наиболее желательной является функциональная связность, при которой все элементы класса или модуля тесно взаимодействуют в достижении определенной цели. Так, например, класс Dog будет функционально связным, если он описывает поведение собаки, всей собаки, и ничего, кроме собаки. Вам советовали его книгу первым же постом, читали?И ещё вопрос. Как оператор в моём случае написать? Ошибка: main.cpp:15: error: no match for 'operator<<' (operand types are 'QTextStream' and 'Rational') cout << "product = " << product << endl; ^ Для примера, можно посмотреть как это сделано в исходниках Qt (правда там для QDataStream, для cout надо std::ostream и std::istream): \src\corelib\tools\qstring.h (и соответствующий .cpp); Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 20, 2014, 10:14 to Old, Johnik
Спасибо за ответы, что операторную функцию можно делать и не дружественной. Для примера, можно посмотреть как это сделано в исходниках Qt (правда там для QDataStream, для cout надо std::ostream и std::istream): \src\corelib\tools\qstring.h (и соответствующий .cpp); Только у меня QTextStream: Код: friend QTextStream& operator<<(QTextStream& stream, const Rational& r); Спасибо! Покапаю исходники Qt. Скажите, пожалуйста, правильно ли я понял, что единственное для чего нужен полиморфизм - это чтобы писать функции, которые принимают указатель на базовый класс и работают с объектами производных классов (так сказать - для уменьшения дублирования кода) Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 20, 2014, 10:31 Только у меня QTextStream: Там было для примера, вот минимум кода: Код
Не надо все воспринимать все буквально, учитесь думать и искать самостоятельно. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 20, 2014, 10:57 Скажите, пожалуйста, правильно ли я понял, что единственное для чего нужен полиморфизм - это чтобы писать функции, которые принимают указатель на базовый класс и работают с объектами производных классов (так сказать - для уменьшения дублирования кода) Единственное или нет - не задумывался. И очень многое придумано "для уменьшения дублирования кода", т.е. это достойная цель. А вообще полиморфизм - одна из самых легких, приятных и полезных вещей в ООП, когда результат/эффект налицо.Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 20, 2014, 13:11 Спасибо, парни!
Вот такая сейчас ошибка, помогите понять: Цитировать error: 'QTextStream& Rational::operator<<(QTextStream&, const Rational&)' must take exactly one argument QTextStream &Rational::operator<<(QTextStream &stream, const Rational &r) ^ Говорит, что должен быть один аргумент. main.cpp Код
rational.h Код
rational.cpp Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 20, 2014, 13:14 Оператор не является членом класса!
rational.cpp Код
Название: Re: Как писать ООП программы? Отправлено: OKTA от Февраль 20, 2014, 13:16 А разве не просто то, что он ждет только один параметр, а не два?))
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 20, 2014, 13:18 Нет! Old прав. И я точно такой же пример приводил.
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 20, 2014, 14:07 Ну может и являться и тогда 1 аргумент. Но это обычно нежелательно как говорили выше. А "friend" автоматически означает НЕ член. Главного человек не понял
Код Внимание: теперь класс Rational уже не может быть использован без Qt. Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 20, 2014, 14:16 Внимание: теперь класс Rational уже не может быть использован без Qt. Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 20, 2014, 14:54 Спасибо большое! Кстати, если написать объявление в классе friend-функции и потом добавить реализацию таким образом: правой кнопкой мыши по функции -> "Refactor" -> "Add difinition in relation.cpp", то добавится такое определение: "QTextStream &Rational::operator<<" вместо "QTextStream &operator<<"
Я ещё понял такую вещь: что если операторная функция - это член класса, то она будет принимать только один аргумент (второй - через this), а если friend или свободная, то два параметра. Помогите разобраться со следующими ошибками: Цитировать D:\Documents\Qt\QtOOP\0004_Shapes\Shapes\main.cpp:19: error: cannot allocate an object of abstract type 'Circle' Shape *pc = new Circle(); ^ D:\Documents\Qt\QtOOP\0004_Shapes\Shapes\main.cpp:22: error: no matching function for call to 'Shape::calcPerimeter(double)' pc->calcPerimeter(2.5); ^ main.cpp Код
shape.h Код
shape.cpp Код
circle.h Код
circle.cpp Код
rectangle.h Код
rectangle.cpp Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 20, 2014, 17:10 Помогите разобраться со следующими ошибками: Цитировать D:\Documents\Qt\QtOOP\0004_Shapes\Shapes\main.cpp:19: error: cannot allocate an object of abstract type 'Circle' Shape *pc = new Circle(); ^ D:\Documents\Qt\QtOOP\0004_Shapes\Shapes\main.cpp:22: error: no matching function for call to 'Shape::calcPerimeter(double)' pc->calcPerimeter(2.5); ^ Все описано в сообщениях. Класс Circle остался виртуальным, поэтому объект этого класса нельзя создать. Что бы он перестал быть виртуальным, нужно в наследуемом классе переопределить calcPerimeter и calcArea так как они определены в базовом классе. Вторая ошибка как раз из-за того, что в базовом классе методы определены без параметров, а в наследниках с параметрами. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 20, 2014, 17:50 Внимание: теперь класс Rational уже не может быть использован без Qt. Я кажется понял, что вот так надо: rational.h Код
rational.cpp Код
Подскажите, пожалуйста, как в main.cpp написать, чтобы работало: Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 20, 2014, 17:57 Класс Circle остался виртуальным, поэтому объект этого класса нельзя создать. Что бы он перестал быть виртуальным, нужно в наследуемом классе переопределить calcPerimeter и calcArea так как они определены в базовом классе. Вторая ошибка как раз из-за того, что в базовом классе методы определены без параметров, а в наследниках с параметрами. У меня для Circle один параметр, а для Rectangle - два. Как быть? Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 20, 2014, 23:16 У меня для Circle один параметр, а для Rectangle - два. Как быть? Параметры объекта передавать в конструкторе.Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 08:38 Параметры объекта передавать в конструкторе. Спасибо за ответ! Но идея, которую я хочу реализовать заключается в том, чтобы от абстрактного класса унаследовать интерфейс: Код
А пользователю предоставить возможность создавать свои классы (унаследованные от моего) с требуемым ему набором параметром для calcPerimeter() и calcArea() circle.h Код
rectangle.h Код
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 21, 2014, 10:17 что мешает сделать так:
Код
Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 10:21 Спасибо! Я понял Вашу идею. А моя, похоже, в данном случае, неприменима.
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 21, 2014, 11:00 rational.cpp Когда этот оператор будет использован из др cpp (не rational.cpp)- получите ошибку линковки, т.к. template должен "находиться в той же единице трансляции", перенесите тело в конец rational.hКод
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 21, 2014, 11:10 Код
По поводу аргументов a, b (не имеют отношения к детали выше). Класс знает все для вычисления периметра и площади, поэтому в любом случае должны быть эти методы без всяких аргументов. Возможно Вы хотели иметь возможность вычислять их без создания класса - тогда так Код Это может быть полезным (хоть и не полиморфным) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 15:09 Когда этот оператор будет использован из др cpp (не rational.cpp)- получите ошибку линковки, т.к. template должен "находиться в той же единице трансляции", перенесите тело в конец rational.h Большое спасибо! Теперь работает! Получается, что все методы с template должны быть в заголовочном файле. Я про это когда-то читал, но забыл, потому что на практике ни разу не попробовал. main.cpp Код
rational.h Код
rational.cpp Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 15:24 Здесь Вы упустили мааааленькую деталь, но без нее - говнокод, с ней - нормально. Какая это деталь? По поводу детали пока не могу ответить. Думаю. Возможно Вы хотели иметь возможность вычислять их без создания класса Спасибо! Как вариант. Да, но тогда выпадает необходимость в базовом абстрактном классе. Хотелось бы, чтобы абстрактный класс был более полезен и указывал разработчикам производных классов, что нужно переопределить функции для рассчёта периметра и площади. По поводу аргументов a, b (не имеют отношения к детали выше). Класс знает все для вычисления периметра и площади, поэтому в любом случае должны быть эти методы без всяких аргументов. Большое спасибо! Я теперь так и сделал. Посмотрите, пожалуйста, в моём коде сейчас есть ли какие-то грубые недочёты: main.cpp Код
shape.h Код
shape.cpp Код
circle.h Код
circle.cpp Код
rectangle.h Код
rectangle.cpp Код
P.S. Узнал, что если у базового класса невиртуальный деструктор, то нельзя будет уничтожить полностью объект производного класса через указатель на базовый (как у меня это сделано в main.cpp), так как не будет вызван деструктор производного класса, таким образом будет утечка памяти. Вот здесь прочитал: "Правило 7: Объявляйте деструкторы виртуальными в полиморфном базовом классе" http://www.e-reading.co.uk/chapter.php/1002058/26/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 21, 2014, 16:25 По поводу детали пока не могу ответить. Думаю. Ладно, не буду мучить - Вы неск раз упустили const, с точки зрения "профи" это грубая, непростительная ошибка. Очень важно дать понять модифицирует ли метод объект или нет. По поводу периметра и площади. Ну вводить их как члены данных в базовый класс совершенно незачем. С фигурами типа Сircle, Rectangle хранить их тоже нет особого смысла т.к. их вычисление "на лету" очень быстро. Но вот появляется более сложная фигура Polygon (замкнутый контур из N вершин, причем N может быть приличным) . Вот для него уже кешировать вычисление периметра есть смысл, а площади - тем более. Развейте эту идею Также напрашиваются общие методы: BoundingRect() // вмещающий пр-к IsConvex() // выпуклая фигура или нет Scale() Да, и для пр-ка традиционно "Height" (а не "Length") Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 20:52 Ладно, не буду мучить - Вы неск раз упустили const, с точки зрения "профи" это грубая, непростительная ошибка. Очень важно дать понять модифицирует ли метод объект или нет. Спасибо большое! Я запомню, что если метод не модифицирует члены-данные объекта, то нужно писать const и что объекты нужно передавать в методы через ссылку на константу, к примеру: void setName(const QString& name), тогда мы гарантируем, что не испортим объект, который нам доверили по ссылке. В моём настоящем коде члены-данные объекта модифицируются, поэтому не const: Код
Да, и для пр-ка традиционно "Height" (а не "Length") Спасибо! Заменил. Также напрашиваются общие методы: BoundingRect() // вмещающий пр-к IsConvex() // выпуклая фигура или нет Scale() Пока это сложно. Не понимаю, к примеру, что такое Scale() (вроде масштабирование). Тут уже чувствуется визуализация (вывод на экран и OpenGL) и реализация draw(). Сейчас это направление развития для меня - неприступная крепость. Но вот появляется более сложная фигура Polygon (замкнутый контур из N вершин, причем N может быть приличным) . Вот для него уже кешировать вычисление периметра есть смысл, а площади - тем более. Развейте эту идею Про полигон подумаю. Спасибо за идею! Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 21, 2014, 21:07 В моём настоящем коде члены-данные объекта модифицируются, поэтому не const: А для чего вы сделали их членами класса?Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 21:36 В моём настоящем коде члены-данные объекта модифицируются, поэтому не const: А для чего вы сделали их членами класса?Потому что периметр и площадь - это общие параметры для всех геометрических фигур на плоскости :) Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 21, 2014, 21:48 Потому что периметр и площадь - это общие параметры для всех геометрических фигур на плоскости :) Которые высчитываются при каждом вызове метода, для чего вы их храните в членах-данных?Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 21, 2014, 22:07 Которые высчитываются при каждом вызове метода, для чего вы их храните в членах-данных? Да, но по моей схеме вызвать методы для расчёта нужно только один раз (а потом мы можем узнавать периметр и площадь с помощью методов: perimeter() и area(), которые расположены в базовом классе). Если меняем, к примеру, радиус, то нужно опять вызвать методы. Может конечно быть ситуация, что, пользователь изменит радиус и забудет вызвать функции для расчёта периметра и площади. Тогда может лучше вызов методов ещё добавить и в функцию setRadius() ? Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 21, 2014, 22:34 Не должно быть в интерфейсе неоднозначностей.
Если я вызову area до calcArea, он мне вернет неправильный результат. Т.е. я должен знать и помнить, что перед получением значения я должен его вычислить с помощью другого метода. Для чего? Пусть area и считает сразу. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 22, 2014, 07:59 Пусть area и считает сразу. Да, это отличный вариант, но посмотрите на мой абстрактный класс Shape. Что от него останется, если я последую Вашему совету? Зачем он тогда нужен? Код
Название: Re: Как писать ООП программы? Отправлено: Bepec от Февраль 22, 2014, 10:35 Чтобы пользователь мог его взять и пользоваться к примеру :)
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 22, 2014, 10:39 Old, смотрите что стало из-за Вас с моим "грандиозным" проектом! Shape теперь не нужен. От всего проекта осталось два малюсеньких файла (не считая демонстрацию в main.cpp). Весь мой полиморфный мир разрушен :(
Получается, что функции для расчёта периметра и площади плохие кандидаты для применения полиморфизма? Для чего класс Shape можно применить? Output: Цитировать Circle: Radius = 5.5 Perimeter = 34.5575 Area = 95.0332 Rectangle: Height = 5 Width = 10 Perimeter = 30 Area = 50 main.cpp Код
circle.h Код
rectangle.h Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 22, 2014, 11:04 объекты нужно передавать в методы через ссылку на константу, к примеру: void setName(const QString& name), тогда мы гарантируем, что не испортим объект, который нам доверили по ссылке. Не только. Константная ссылка разрешает создание временного объекта, напрКод Здесь будет создан временный (безымянный) объект QString, он будет подан в ф-цию и удален после того как ф-ция вернет управления. А если аргумент - не константная ссылка - так нельзя. Конечно это "совсем просто", но вещь базовая и ее надо изучить очень тщательно Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 22, 2014, 11:15 Не только. Константная ссылка разрешает создание временного объекта, напр Код Здесь будет создан временный (безымянный) объект QString, он будет подан в ф-цию и удален после того как ф-ция вернет управления. А если аргумент - не константная ссылка - так нельзя. Конечно это "совсем просто", но вещь базовая и ее надо изучить очень тщательно Спасибо! Попытаюсь понять на примере. Почему он мне выдаёт сообщение: Цитировать main.cpp:19: error: no matching function for call to 'Person::Person(const char [5])' Person ivan("Ivan"); ^ main.cpp Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 22, 2014, 11:20 Old, смотрите что стало из-за Вас с моим "грандиозным" проектом! Shape теперь не нужен. От всего проекта осталось два малюсеньких файла (не считая демонстрацию в main.cpp). Весь мой полиморфный мир разрушен :( Напротив, они отличные кандидаты для полиморфизма. Получается, что функции для расчёта периметра и площади плохие кандидаты для применения полиморфизма? Для чего класс Shape можно применить? Код Такое вычисление имеет смысл, но оно никак не зависит от самого класса, его членов. Значит это static метод. Но так Вам надо иметь радиус "на стороне". Хорошо увязать это вместе, напр Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 22, 2014, 11:24 Спасибо! Попытаюсь понять на примере. Почему он мне выдаёт сообщение: А разве у Вас есть конструктор принимающий QString? И зачем метод name возвращает QString по значению? Для этого нет никаких оснований, правильно вернуть константную ссылкуНазвание: Re: Как писать ООП программы? Отправлено: Old от Февраль 22, 2014, 11:47 Old, смотрите что стало из-за Вас с моим "грандиозным" проектом! Shape теперь не нужен. От всего проекта осталось два малюсеньких файла (не считая демонстрацию в main.cpp). Весь мой полиморфный мир разрушен :( Почему? Полиморфизм можно оставить. :)Смотрите: Код
Код
Тогда можно будет считать perimeter и area для любой фигуры, не задумываясь какая она конкретно. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 22, 2014, 12:26 Общее замечание - излишнее упрощение. Не хочется возиться с полигоном - ведь это якобы "не имеет отношения к С++". Формально так, на деле - нет. Будет больше ф-ционала - будет и больше архитектуры, проблем что нужно решать. А месить простейшие круг и пр-к - да тут и классы-то (по большому счету) не нужны. И вообще, культурный человек должен уметь подсчитать площадь полигона :)
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 22, 2014, 18:31 Большое спасибо за ответы! Я их постепенно буду разбирать :)
А разве у Вас есть конструктор принимающий QString? Большое спасибо! Это я поторопился. Добавил конструктор принимающий const QString&. И зачем метод name возвращает QString по значению? Для этого нет никаких оснований, правильно вернуть константную ссылку Да, точно! Ведь переменная mName будет всегда и это не тот случай, когда мы не можем возвращать ссылку (то есть, в нашем случае, объект, на который указывает ссылка, не будет уничтожен): http://www.e-reading.co.uk/chapter.php/1002058/56/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Вот нужно будет мне ещё понять, почему возвращать именно константную ссылку... А если она будет неконстантная? Вот, что я понял. Получается, что если мы вызываем метод вот так: Код: ivan.setName("Ivan"); то конструируется новый временный объект, который передаётся в функцию через ссылку, поэтому не вызывается конструктор копирования и это быстрее по сравнению с передачей по значению. Хотя мы врядли передадим большое имя, но лучше приучаться сразу передавать через константную ссылку. Кстати, я пробовал писать без const, вот так: void setName(QString& name) выдаёт: Цитировать main.cpp:31: error: no matching function for call to 'Person::setName(const char [5])' ivan.setName("Ivan"); ^ А если так: void setName(const QString& name), то нормально: main.cpp Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 22, 2014, 18:55 А если так: void setName(const QString& name), то нормально: Не совсем, это конструктор, правильно (во всяком случае точнее) использовать инициализацию .. Код
Код
По поводу "изменилась ссылка", "быстрее" и.т.п. Не в этом дело. Пример: пусть есть ф-ция Код В чем разница между Код и Код ??? Название: Re: Как писать ООП программы? Отправлено: Hrundel от Февраль 23, 2014, 02:39 В ООП нужно рассуждать структурно. Одна из лучших структур наиболее ярко демонстрирурующая ООП - это дерево. Любое дерево. Так например, классификация животного мира.
Базовый класс от которого происходят все животные и у них У ВСЕХ есть свойcтва базового класса = животное У животного есть одно и очень важное свойсто - оно живое. Раз оно живое значит у него есть как минимум три состояния. 1. рождение или появление на свет 2. жизнь 3. умирание или смерть. Код
От этого класса наследуются царства хордовые и безпозвоночные Код От царства безпозвоночных наследуются Черви и Насекомые От царства хордовых Рыбы, Амфибии, Птицы и Млекопитающие От млекопетающих звери и еще пара *(уже не помню) От зверей сумчатые, плацентарные и еще один *(опять не помню) и так далее до какой-нибудь мыши полевки обыкновенной. При этом у каждого нового класса в этом дереве есть свои новые функции или особенности. Но каждый из них наследует все свойства классов от которых происходит. Каждый из классов может иметь малюсенькую функцию, поэтому не обязательно каждый класс прописывать в отдельном файле. Их можно все писать в одном заголовочном файле. Для того, чтобы составить такую сложную иерархию - нужен план. Для составления такого плана используется UML. Иначе потеряешь обозримость проекта. Разрабы используют или Entrprice Architekt или Visual Paradigm. Я предпочитаю второе. Самое приятное в этих программах то, что после составления очень сложной и увесистой модели можно сгенерировать код в C++. На Visual Paradigm код получается рабочий. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 23, 2014, 14:44 В ООП нужно рассуждать структурно. Одна из лучших структур наиболее ярко демонстрирурующая ООП - это дерево. Любое дерево. Так например, классификация животного мира. Спасибо за идею с животными! Интересно поразвивать будет. Кстати, у Гради Буч вся книга посвящена таким деревьям (такой подход применим во всех областях науки, человеческой жизни, природы, игр и т.д.). Я введение прочитал. Хорошо, что напомнили. Нужно её проработать до конца. На всякий случай напоминаю: Перевод: http://rutracker.org/forum/viewtopic.php?t=3343958 Оригинал: http://kickass.to/object-oriented-analysis-and-design-with-applications-3rd-editio-t2753820.html Каждый из классов может иметь малюсенькую функцию, поэтому не обязательно каждый класс прописывать в отдельном файле. Их можно все писать в одном заголовочном файле. Вот это пока неочевидно. Примеров никаких не видел и не придумывал. Я заметил, что когда делаешь что-то, то обычно первый раз делаешь неправильно, а потом, когда видишь, как правильно, и переделываешь своё под правильное, то запоминается гораздо лучше. Несколько классов в одном файле, это пока для меня непостижимо.Для того, чтобы составить такую сложную иерархию - нужен план. Для составления такого плана используется UML. Иначе потеряешь обозримость проекта. Разрабы используют или Entrprice Architekt или Visual Paradigm. Я предпочитаю второе. Самое приятное в этих программах то, что после составления очень сложной и увесистой модели можно сгенерировать код в C++. На Visual Paradigm код получается рабочий. Большое спасибо! Вот такие инструменты мне обязательно нужно освоить :)По поводу "изменилась ссылка", "быстрее" и.т.п. Не в этом дело. Пример: пусть есть ф-ция Спасибо! Чуть позже доберусь до этого. Пока не подсказывайте. Сам подумаю :)Я восстановил полиморфизм и добавил возможность считать периметр и площадь через статические функции. Примечание. Упростил себе работу с несколькими ветками развития проекта. Из консоли (из под Far'а) переключаю ветки в git и Qt Creator моментально перегружает проект. Пошагово описал здесь: http://www.prog.org.ru/topic_26393_0.html Теперь мы можешь установить радиус (с помощью функции setRadius(double radius)), потом вызвать полиморфные функции perimeter() и area(). Я понял свою ошибку, когда писал calcPerimeter() и calcArea(). Я боялся, что производить расчёт при каждом вызове - это плохой стиль. Я думал, что нужно один раз посчитать, а пересчитывать только при смене параметров. Периметр и площадь считаются быстро. Но вот если у нас будет сложная фигура (я унаследую её от Shape). Вот создам я новый класс Полигон (многоугольник) и появятся проблемы с пересчётом. Сейчас прорабатываю эту идею. Теперь приходит понимание, что хорошо спроектированная система будет лучше реагировать на изменения требований. Меня напрягает, что при смене требований мне нужно переписывать всю систему целиком. Хорошо, что пока система не очень большая (мягко говоря). Надеюсь, с опытом будет приходить понимание и скорость. Old, я видел в Вашем коде (из ответа #58) ключевое слово explicit перед конструктором. Я думаю, что это связано с приведением типов. Сейчас изучаю это провило: "Правило 27: Не злоупотребляйте приведением типов" http://www.e-reading.co.uk/chapter.php/1002058/69/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Остановился на таком варианте. Пожалуйста, укажите на грубые недочёты, если они есть. Output Цитировать static perimeter: 18.8496 p = 18.8496 s = 28.2743 p = 30 s = 50 main.cpp Код
shape.h Код
circle.h Код
rectangle.h Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 23, 2014, 14:49 Скажите, пожалуйста, а реально ли реализовать функцию draw() для моих классов через OpenGL? Это очень сложно?
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 23, 2014, 15:28 Скажите, пожалуйста, а реально ли реализовать функцию draw() для моих классов через OpenGL? Это очень сложно? Реально и не сложно, только эта тема уже будет не ООП. :)Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 23, 2014, 15:53 Периметр и площадь считаются быстро. Но вот если у нас будет сложная фигура (я унаследую её от Shape). Вот создам я новый класс Полигон (многоугольник) и появятся проблемы с пересчётом. Сейчас прорабатываю эту идею. Очень многие решения зависят от того "а что за плечами", т.е. какой код уже написан? Сейчас у Вас "аж ничего", простейшие Circle/Rectangle переделываются за неск минут как угодно. В результате получается довольно легкое "порхание бабочки", в котором нет ничего плохого - но и толку немного. Поэтому-то люди и советуют типа "возьми реальную задачу". Но то легко сказать, а реально - стоит ли на много недель (минимум) углубляться в "нечто" (специфику/матчасть) только для целей обучения? С этой точки зрения полигон - хороший вариант. Он и достаточно сложен (так резво как с простыми шейпами не выйдет) - и достаточно прост, ну максимум день на освоение простой геометрии. В общем, как говорил один мой заказчик:Цитировать Ну подумай-подумай. А я пока чайку нагною :)По поводу животных. Красиво, впечатляет. Но в библии есть ответ и на это - ну на то она и библия. Название: Re: Как писать ООП программы? Отправлено: Авварон от Февраль 23, 2014, 19:32 А разве у Вас есть конструктор принимающий QString? И зачем метод name возвращает QString по значению? Для этого нет никаких оснований, правильно вернуть константную ссылку Неправильно. С точки зрения производительности - да, с точки зрения всего остального - нет. Во-первых, теряется гибкость (если было 2 связанных геттера - Document::filePath() и Document::name() (aka QFileInfo(filePath()).fileName()) то что, при кешировании имени менять сигнатуру? нарушается бинарная совместимость, да и код странный - один метод возвращает const QString &, 2й QString). Во-вторых, это небезопасно - может найтись умник, к-ый снимет const со ссылки и возьмет да и поменяет. Не, ну а чо - "квикфикс, сроки горят, потом исправлю"). ЗЫ: Ну то есть если вы юзаете std::string, где корову забанили, то это имеет смысл. Для QString смысла нет. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 24, 2014, 10:10 Скажите, пожалуйста, а реально ли реализовать функцию draw() для моих классов через OpenGL? Это очень сложно? Реально и не сложно, только эта тема уже будет не ООП. :)Спасибо! Вы правы. Специфику OpenGL мы здесь обсуждать не будем. Предлагаю взглянуть на рисование фигур с точки зрения ООП (а OpenGL - это просто будет второстепенный инструмент). Объекту какого класса предложить рисование фигур? Мне предлагали сделать функцию draw() полиморфной в Shape, а потом реализацию писать в дочерних классах, потому что "функция знает как себя рисовать" (что-то в этом роде). А я считаю, что нужно завести для рисования специальный класс с методом draw(). В этот метод мы будем передавать константную ссылку на Shape (и ещё смещение по x и y от начала координат, а так же толщину линии) Вот так: viewer.h Код
Но теперь я в тупике. Как объект класса Viewer отличит круг от прямоугольника? А если будет другая фигура? Может передавать в draw массив координат точек вершин (который будет внутри Shape)? Как вы полагаете? Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 24, 2014, 10:34 Но теперь я в тупике. Как объект класса Viewer отличит круг от прямоугольника? А если будет другая фигура? Может передавать в draw массив координат точек вершин (который будет внутри Shape)? Как вы полагаете? Здесь точно та же ситуация как и с std::ostream или QTextStream Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 24, 2014, 11:08 Неправильно. С точки зрения производительности - да, с точки зрения всего остального - нет. Во-первых, теряется гибкость (если было 2 связанных геттера - Document::filePath() и Document::name() (aka QFileInfo(filePath()).fileName()) то что, при кешировании имени менять сигнатуру? нарушается бинарная совместимость, да и код странный - один метод возвращает const QString &, 2й QString). Во-вторых, это небезопасно - может найтись умник, к-ый снимет const со ссылки и возьмет да и поменяет. Не, ну а чо - "квикфикс, сроки горят, потом исправлю"). Не в курсе о каком кешировании Вы говорите.Код Это все вещи разные. В первом случае ясно показано что строка - член класса, вызов очень быстр и ничем не чреват. Часто вызывающий все равно копирует строку в переменную - но то уже его дело. А во втором ясно только что класс умеет выдать строку, а как - дело темное. Может просто вернет член, а может и будет как-то вычислять. Возможно этот вызов затратен или вообще будет выдано не то что надо - напр у класса еще не установлены нужные данные. Поэтому возвращать по значению "на всякий случай" не кажется мне хорошим стилем. Третий вариант в большинстве случаев просто плох - оказывается что геттеры/сеттеры просто игрушки, так, "чтобы по книжке было". А дошло до дела - вот и (слегка) замаскированный "public" :) Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 24, 2014, 11:19 Мне предлагали сделать функцию draw() полиморфной в Shape, а потом реализацию писать в дочерних классах, потому что "функция знает как себя рисовать" (что-то в этом роде). А я считаю, что нужно завести для рисования специальный класс с методом draw(). Обоснуйте свое решениеВ этот метод мы будем передавать константную ссылку на Shape (и ещё смещение по x и y от начала координат, а так же толщину линии) Вот так: А откуда Вы возьмете смещения? Они явно принадлежат шейпу, его член(ы). Иначе как Вы будете их хранить? Контейнер шейпов + еще (параллельно) контейнер смещений? :)Толщина линии. Из той же оперы: цвет, заливать внутренности или нет и.т.п.. Здесь возможны варианты. Вполне нормально если сама шейпа знает свою толщину линии - напр сейчас она "выбрана". Т.е. тоже член. Но также возможно что рисующий хочет какую-то одну толщину для всех. Как это увязать? Название: Re: Как писать ООП программы? Отправлено: Hrundel от Февраль 24, 2014, 11:35 Но теперь я в тупике. Как объект класса Viewer отличит круг от прямоугольника? А если будет другая фигура? Может передавать в draw массив координат точек вершин (который будет внутри Shape)? Как вы полагаете? Ну с этим-то как раз проще всего - на то и полиморфизм. Мне кажеться ты опять думаешь не в ту сторону. После генерализации используются ТОЛЬКО листья дерева. Это значит, что к руту (корню) Shape тебе уже обращаться не нужно. Объекты потомки Shape, по логики вещей, не могут существовать без Viewer, иначе их существование становится безсмысленным. Поэтому создаваться они должны для Viewer. То есть внутри этого класса. Вот, это как раз и есть вопросы которыми в основном занят разработчик архитектуры. Как сделать все логичным, оправданным, понятным, простым и удобным! Поэтому если ты хочешь рисовать круг, то пишешь Код
Мне предлагали сделать функцию draw() полиморфной в Shape, а потом реализацию писать в дочерних классах, потому что "функция знает как себя рисовать" (что-то в этом роде). А я считаю, что нужно завести для рисования специальный класс с методом draw(). В этот метод мы будем передавать константную ссылку на Shape (и ещё смещение по x и y от начала координат, а так же толщину линии) Вот так: Думаю, что твой путь не самый простой для реализации, да и по понятности кода, в нем будет меньше логики. Просто напиши в Shape виртуальную функцию и реализуй для каждого отдельно, так проще, понятнее, логичнее. И вообще Shape должен содержать все возможные виртуальные функции, которые могут быть в дальнейшем использованы для потомков. Например: move(int x, int y), hide(), show(), scale(float u, float v), setFillColor(QColor*), setShapeColor(QColor*) и все тому подобное. Если оно, кончно, планируется к использованию. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 24, 2014, 12:44 Объекты потомки Shape, по логики вещей, не могут существовать без Viewer, иначе их существование становится безсмысленным. Поэтому создаваться они должны для Viewer. То есть внутри этого класса. Не вижу никаких оснований для такого вывода. Напр объекты могут быть загружены из файла и сохранены в др формате - никакого вьюера и близко нет. Или наоборот, могут быть использована неск вьюерами сразу.Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 24, 2014, 13:21 Это все вещи разные. Так Авварон вам про это и говорит.Это настолько разные вещи, что у этих методов разные сигнатуры и при изменении прототипа с первого на второй (или наоборот) полетит ABI. А менять их может заставить жизнь при развитии проекта. Например, вы написали такой метод: Код который просто возвращает ссылку на поле класса, а через год, его нужно поменять так, что бы он начал возвращать временную строку, потому что этот путь уже не просто ссылка на поле, а формируется внутри filePath1 по хитрому алгоритму: Код Так просто это сделать не получиться, нужно будет отказываться от возврата константной ссылки, вместе с бинарной совместимостью. Приплыли. Поэтому, и нужно возвращать по значению. :) Название: Re: Как писать ООП программы? Отправлено: Hrundel от Февраль 24, 2014, 13:21 Объекты потомки Shape, по логики вещей, не могут существовать без Viewer, иначе их существование становится безсмысленным. Поэтому создаваться они должны для Viewer. То есть внутри этого класса. Не вижу никаких оснований для такого вывода. Напр объекты могут быть загружены из файла и сохранены в др формате - никакого вьюера и близко нет. Или наоборот, могут быть использована неск вьюерами сразу.Ну... Тут ты меня сразу уговорил :) Код
Я так понял, что он хочет это для OpenGL использовать. Следовательно, напишет внутри GL-ные функции рисования и вперед. Или класс должен быть универсальным? И подходить для QPainter? Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 24, 2014, 20:07 Вот аргументы почему draw() нужно сделать методом класса Viewer, а не методом класса Shape:
Фигура - это объект, который не может совершать действий (к примеру, рисовать сама себя). Да, фигура, в моём случае, может расcчитать свою площадь и т.д., но для пользователя это незаметно, ведь он запрашивает площадь так: s = circle.area(). Можно сказать, что фигура обладает определённым набором характеристик (цвет, координаты и т.д.). В моём случае, объект класса Viewer - это художник. У него есть холст и набор красок. Мы отдаём ему фигуру (одну за другой и viewer сохраняет их в массив), которая хранит в себе список своих характеристик. Художнику не нужно знать, что это за фигура. Он смотрит на список характеристик и находит там координаты точек. Выставляет все точки на холст и соединяет определёнными линиями, закрашивает определённым цветом, располагает фигуры в определённых местах и т.д. А "компьютерному художнику" приходится хранить у себя массив фигур, чтобы перерисовывать, когда мы, к примеру, меняем размер окна (или перекрываем окно другим окном). Я ещё не до конца реализовал. С помощью addForPainting(const myShapes::Shape &ps) я буду добавлять фигуру для рисования в закрытый массив std::vector<myShapes::Shape> shapes; и перерисовывать с помощью draw() весь массив фигур из shapes. viewer.h Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 24, 2014, 20:17 Намучился с одной ошибкой. Оказывается свои классы нужно прятать в своё пространство имён. Мой класс Rectangle начал конфликтовать с включением #include <QGLWidget> Пришлось сделать так:
shape.h Код
rectangle.h Код
Название: Re: Как писать ООП программы? Отправлено: Hrundel от Февраль 24, 2014, 20:39 Вот аргументы почему draw() нужно сделать методом класса Viewer, а не методом класса Shape ... [/quote] Ну да, а откуда Circle возьмет контекст рисования? Игорь, я тебя сильно уважаю, но тут ты сказал не подумав! Конечно, дико извеняюсь - но фигня это всё !!! Если хочешь помещать потомков Shape в QGraphicsView, то ничего такого не надо!!! Все потомки имеют метод paint и рисуют себя сами!!! И для OpenGL та же ерунда действует. В заголовке Код
Дальше все от него наследуются, переопределяют paint и рисуют что хотят. Название: Re: Как писать ООП программы? Отправлено: Hrundel от Февраль 24, 2014, 20:47 Оказывается свои классы нужно прятать в своё пространство имён. Мой класс Rectangle начал конфликтовать с включением #include <QGLWidget> И здесь дико извеняюсь - полная ерунда!!! Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 25, 2014, 08:07 Реализовать рисование у меня пока не получается. Вернусь к этому позже.
Помогите мне, пожалуйста, понять вот это правило: "Правило 37: Никогда не переопределяйте наследуемое значение аргумента функции по умолчанию" http://www.e-reading.bz/chapter.php/1002058/95/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Сначала автор приводит плохой пример, что не стоит переопределять аргумент поумолчанию наследуемой виртуальной функции. Так как виртуальные функции связываются динамически, а аргументы поумолчанию - статически: main.cpp Код
Чтобы было правильно, нужно написать то же самый код только изменить одну единственную строку (то есть убрать аргумент поумолчанию из класса потомка) Код
Но я не могу понять зачем автор приводит подход называемый: идиома невиртуального интерфейса (NVI) (см. код далее) Что нам это даёт? Чем это лучше предыдущего подхода (когда мы просто не переопределяем аргумент)? При подходе NVI мы так же не можем переопределить аргумент поумолчанию, так как в C++ перезагружать невиртуальные функции нельзя. Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 25, 2014, 09:19 Я понял. Автор использовал идиому невиртуального интерфейса (NVI), чтобы пользователь класса Shape не смог переопределить draw(), то есть не стал бы писать свой аргумент поумолчанию. Пользователь увидит, что draw() невиртуальна и не станет её переопределять (ибо нельзя).
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 10:54 Так просто это сделать не получиться, нужно будет отказываться от возврата константной ссылки, вместе с бинарной совместимостью. Да, напр было такое использованиеПриплыли. Код Это придется переделать - ну, на мой взгляд, в этом больше хорошего. Возможно я просто смирюсь с копированием, но может и придумаю новое решение - если это место критично. И компилятор меня "ткнет носиком". А в погоне за (мнимой) универсальностью легко можно загнать проблему "вглубь" Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 11:02 ну, на мой взгляд, в этом больше хорошего. А что в этом хорошего?А в погоне за (мнимой) универсальностью легко можно загнать проблему "вглубь" В погоне за мнимой преждевременной оптимизацией можно упустить гораздо более важные проблемы. :)Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 11:40 Помогите мне, пожалуйста, понять вот это правило: "Правило 37: Никогда не переопределяйте наследуемое значение аргумента функции по умолчанию" http://www.e-reading.bz/chapter.php/1002058/95/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Мне кажется Вы погнались за второстепенными вещами, а ведь уже получили массу гораздо более полезных уроков - неплохо бы их заучить основательно1) Не давайте общих имен (типа Rectangle) - велика вероятность они пересекутся. Простой и хороший способ - начинать свой класс (тип) с большой буквы, напр я использую "С". Написав CRectangle ясно видно - это мой класс. Др букву "T" я использую для своих typedef. Имена членов классов лучше начинать с "m" или "m_" 2) Использование namespace - палка о двух концах. Не стоит его заводить "просто так", напр в Вашем случае легко обойтись без него. 3) Очень важная вещь прошла мимо Вашего внимания: базовый инструментарий. Вы привлекли Qt - это важное, принципиальное решение. Тогда встает вопрос - так может и шейпы лучше делать средствами Qt? Напр освоить QGraphicsItem. Да, так Вы много не на-архитектурите, увы - все уйдет в чтение букваря. Но практический результат будет на порядок выше. Задаваться вопросом "а не изобретаю ли я велосипед?" приходится всем и всегда. Ладно, вернемся к Вашему проектированию Вот аргументы почему draw() нужно сделать методом класса Viewer, а не методом класса Shape: 1) Типичная (очень популярная) ошибка - неудачный выбор std::vector. Вспомните как "уплывали" адреса - теперь уже трудно будет подавать элементы вектора по указателю/ссылке, все время придется оглядываться "а не изменился ли вектор". Здесь хороший выбор QListФигура - это объект, который не может совершать действий (к примеру, рисовать сама себя). Да, фигура, в моём случае, может расcчитать свою площадь и т.д., но для пользователя это незаметно, ведь он запрашивает площадь так: s = circle.area(). Можно сказать, что фигура обладает определённым набором характеристик (цвет, координаты и т.д.). В моём случае, объект класса Viewer - это художник. У него есть холст и набор красок. Мы отдаём ему фигуру (одну за другой и viewer сохраняет их в массив), которая хранит в себе список своих характеристик. Художнику не нужно знать, что это за фигура. Он смотрит на список характеристик и находит там координаты точек. Выставляет все точки на холст и соединяет определёнными линиями, закрашивает определённым цветом, располагает фигуры в определённых местах и т.д. А "компьютерному художнику" приходится хранить у себя массив фигур, чтобы перерисовывать, когда мы, к примеру, меняем размер окна (или перекрываем окно другим окном). Я ещё не до конца реализовал. С помощью addForPainting(const myShapes::Shape &ps) я буду добавлять фигуру для рисования в закрытый массив std::vector<myShapes::Shape> shapes; и перерисовывать с помощью draw() весь массив фигур из shapes. 2) С какой это стати "художник" хранит все шейпы? Они могут прекрасно жить без всякого художника (см пример выше). Да, машине рисования они должны быть известны (иначе нечего рисовать), но это все, добавлением/удалением/редактированием шейпов рисование не занимается. 3) Аргументы "фигура не должна уметь себя рисовать" пока неубедительны, и что Вы предлагаете взамен - неясно. Попробуйте ответить на вопрос "а что плохого если фигура сама себя рисует?", он уже звучал выше Да, и терминов типа "холст" лучше избегать, уж очень отдает дилетантством :) К тому же в современном рисовании нет аналога/подобия "холста" Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 11:46 2) Использование namespace - палка о двух концах. Не стоит его заводить "просто так", напр в Вашем случае легко обойтись без него. Можно подробней о "двух концах", в чем по вашему может быть проблема и почему по вашему его не стоит заводить просто так? И когда же по вашему его стоит заводить? :)А я бы рекомендовал его использовать почаще, ибо он прекрасно справляется со своей ролью. Нужно просто с ним разобраться один раз. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 13:01 Можно подробней о "двух концах", в чем по вашему может быть проблема и почему по вашему его не стоит заводить просто так? И когда же по вашему его стоит заводить? :) Пример где я мучался продолжая разработку предшественников. Первый написалА я бы рекомендовал его использовать почаще, ибо он прекрасно справляется со своей ролью. Нужно просто с ним разобраться один раз. Код Ничего плохого нет. Второй писал др фрагмент и сделал так Код Т.к. "сопля была слишком длинной". Третий перелил это в свой namespace. В результате я не мог быстро посмотреть описание самого класса, браузер выходит на typedef - и все :) Много времени съедается на отслеживание пересечений, а отделаться using не удается. Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 13:09 Много времени съедается на отслеживание пересечений, а отделаться using не удается. Дааа. Главное что бы эти "предшественники" не пользовались шаблонами, никогда. А с дуру можно что хош сломать. :)Совет остается в силе: Нужно просто с ним разобраться один раз. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 14:21 Совет остается в силе: Так резво не выйдет. Надо пописать типа "MyNamespace::" раз так тыщу, чтобы почувствовать уместно/нужно ли оно или так, для понтуНужно просто с ним разобраться один раз. Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 14:24 Так резво не выйдет. Надо пописать типа "MyNamespace::" раз так тыщу, чтобы почувствовать уместно/нужно ли оно или так, для понту Ну это только если с ними не разобраться "MyNamespace::" нужно писать раз так тыщу. Если не компетентен, то должен страдать. Да. Так везде. :)Название: Re: Как писать ООП программы? Отправлено: _OLEGator_ от Февраль 25, 2014, 14:37 Если не компетентен, то должен страдать. Да. Так везде. :) Браво, аплодирую) Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 14:55 Ну это только если с ними не разобраться "MyNamespace::" нужно писать раз так тыщу. Если не компетентен, то должен страдать. Да. Так везде. :) Так Вы же советуете применять их почаще - не я. И человеку свойственно переоценивать собственную компетентность - как и недооценивать компетентность других :)Вот хоть эти шейпы. Ничего против namespace возразить не могу, вроде уместен. Но с др стороны имена классов Rectangle и Circle все равно плоховаты - так и надо это исправить. После этого какая необходимость в namespace? Аж никакой, ну и чего с ним спешить? Добавить его никогда не поздно, не надо решать проблемы до их поступления. Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 15:04 Вот хоть эти шейпы. Ничего против namespace возразить не могу, вроде уместен. Но с др стороны имена классов Rectangle и Circle все равно плоховаты - так и надо это исправить. После этого какая необходимость в namespace? Аж никакой, ну и чего с ним спешить? Добавить его никогда не поздно, не надо решать проблемы до их поступления. Все проблемы нужно решать заранее, потом решение может быть очень дорогим.Про бинарную совместимость напомнить? Часто нельзя так просто поменять сигнатуры функций и методов, а библиотек написано уже огромное количество и колизии имен очень возможны. В крупных проектах. А проблем с пространствами нет никаких, и ничего по тыще раз набирать не нужно. Нужно разобраться. :) Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 15:45 Все проблемы нужно решать заранее, потом решение может быть очень дорогим. Не думаю что Вам всегда удавалось все решить заранее :) Скорее всего начиная задачу Вы делаете вещи хорошо зарекомендовавшие себя в прошлом (в том числе и сразу заводите namespace). Ну так на здоровье - но есть и др подходыа библиотек написано уже огромное количество и колизии имен очень возможны. В крупных проектах. С этим никто не спорит, но совершенно незачем самому напрашиваться на коллизии давая такое имя как Rectangle. Скромнее надо быть :)Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 15:50 С этим никто не спорит, но совершенно незачем самому напрашиваться на коллизии давая такое имя как Rectangle. Скромнее надо быть :) Это даже не смешно, а какое имя я должен дать? Такое "asdasd"?Еще раз повторю, в пространствах имен нет никаких проблем, не нужно по тыще раз ничего набирать, если научиться ими пользоваться. Поэтому, отказываться от них по вымышленным причинам не вижу смысла. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 25, 2014, 18:17 Это даже не смешно, а какое имя я должен дать? Такое "asdasd"? К таким извращениям я не призывал - достаточно добавить "личный префикс" который обычно 1 буква, полезно во всех отношениях.Еще раз повторю, в пространствах имен нет никаких проблем, не нужно по тыще раз ничего набирать, если научиться ими пользоваться. Поэтому, отказываться от них по вымышленным причинам не вижу смысла. Вы же не забывайте добавлять типа "я считаю, мое мнение.." :) А то звучит слишком категорично. У Вас одна точка зрения, у меня другая (и ей тоже не один день), это нормально.Ладно, что-то ТС примолк. Ох и резво он стартовал - как бы не "перегорел" :) Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 18:24 К таким извращениям я не призывал - достаточно добавить "личный префикс" который обычно 1 буква, полезно во всех отношениях. Так это корявая попытка сделать то, что делает namespace. :) Для чего извращаться, если есть полноценное решение.Вы же не забывайте добавлять типа "я считаю, мое мнение.." :) А то звучит слишком категорично. Вовсе нет. У Вас одна точка зрения, у меня другая (и ей тоже не один день), это нормально. Пока что вы не показали не одного убедительного довода, кроме незнания предмета.Ладно, что-то ТС примолк. Ох и резво он стартовал - как бы не "перегорел" :) А что там резвого, по моему кучу времени он занимается какой-то ерундой с двумя классами в которых два метода. Я бы сказал, что он ничего не делает.Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 25, 2014, 21:30 Помогите, пожалуйста, найти ошибку. Говорит:
Цитировать GameCharacter\functions_for_healthcalc.h:9: error: 'GameCharacter' does not name a type int defaultHealthCalc(const GameCharacter& gc); ^ В этом файле: Код
Если несложно - скомпилируйте у себя. Вот отсюда можно скачать ("Download ZIP" справа) https://github.com/8Observer8/GameCharacter/tree/strategyWithPointers Очень буду признателен. Заранее спасибо. P.S. Это попытка посмотреть в деле этот пример: http://www.e-reading.bz/chapter.php/1002058/88/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Название: Re: Как писать ООП программы? Отправлено: gil9red от Февраль 25, 2014, 21:43 Код
Код
Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 25, 2014, 21:48 2gil9red
8Observer8 Держите. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 25, 2014, 21:50 Спасибо огромное, парни! Завтра доделаю :)
Название: Re: Как писать ООП программы? Отправлено: gil9red от Февраль 25, 2014, 21:54 2gil9red Не успел =)8Observer8 Держите. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 09:15 Объясните, пожалуйста, почему в этом коде нужно объявлять класс "class GameCharacter;" Я же включаю заголовок #include "gamecharacter.h":
Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 09:32 Почти всё исправил. Помогите, пожалуйста, доделать. Сейчас говорит, что:
Цитировать GameCharacter\gamecharacter.h:15: error: 'defaultHealthCalc' is not a member of 'GameStuff' explicit GameCharacter(HealthCalcFunc hcf = GameStuff::defaultHealthCalc) Код: https://github.com/8Observer8/GameCharacter/tree/strategyWithPointers Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 10:01 Я пытаюсь вот этот пример реализовать: http://www.e-reading.bz/chapter.php/1002058/89/Mayers_-_Effektivnoe_ispolzovanie_CPP.html
Подключаю заголовок: Код
Пишу вот такую строчку: Код
Но компилятор не находит tr1. Почему? Как написать? Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 26, 2014, 10:06 Но компилятор не находит tr1. Почему? Как написать? std::functionНазвание: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 10:27 Но компилятор не находит tr1. Почему? Как написать? std::functionГоворит, что: Цитировать main.cpp:8: error: 'function' in namespace 'std' does not name a type typedef std::function func; ^ Код
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 26, 2014, 10:36 указывать надо так:
Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 10:39 Всё равно говорит, что:
Цитировать main.cpp:8: error: 'function' in namespace 'std' does not name a type typedef std::function func; ^ Код
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 26, 2014, 10:45 Какой у вас компилятор?
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 10:47 Вот такая сборка Qt: Qt 5.2.0 for Windows 32-bit (MinGW 4.8, OpenGL, 689 MB)
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 26, 2014, 10:48 в .pro необходимо добавить:
Код: QMAKE_CXXFLAGS += -std=c++11 Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 10:50 в .pro необходимо добавить: Код: QMAKE_CXXFLAGS += -std=c++11 Спасибо огромное! Работает :) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 11:01 Только меня смущает, что имя "function" не отображается в подсказках:
(http://i7.pixs.ru/storage/6/7/2/137png_3528066_11027672.png) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 12:19 Помогите, пожалуйста, понять и исправить эту ошибку:
Цитировать 042_typename\main.cpp:44: error: expected template-name before '<' token class Derived: public Base<T>::Nested { // СЃРїРёСЃРѕРє базовых классов: ^ Код
P.S. Это код из правила: http://www.e-reading.bz/chapter.php/1002058/106/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 12:26 Я нашёл ошибку :)
Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 12:49 Помогите, пожалуйста, понять следующую вещь. Я так понял, что когда мы передаём объекты элементарных типов (int, double и т.д.), то передавать по ссылке на константу или по значению - разницы нет. Для объектов отстальных типов нужно использовать передачу по ссылке на константу. А как обстоит дело и итераторами? Передавать по ссылке на константу или по значению?
Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 26, 2014, 13:23 По значению. Вообще если класс "достаточно мал" - он обычно подается/возвращается по значению. Напр (Q)Point, (Q)Rect, (Q)Size
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 13:28 Спасибо! В данном случае - понятно. А если это класс Person, в котором: имя, фамилия, отчество и дата рождения? Это довольно маленький класс.
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 26, 2014, 13:46 По значению. Вообще если класс "достаточно мал" - он обычно подается/возвращается по значению. Напр (Q)Point, (Q)Rect, (Q)Size в Qt эти классы в большинстве мест передаются по константной ссылке.Спасибо! В данном случае - понятно. А если это класс Person, в котором: имя, фамилия, отчество и дата рождения? Это довольно маленький класс. Если класс больше чем int, double и т.д., то он обычно передается по константной ссылке.По поводу итераторов: Итераторы содержат как правило всего лишь один указатель на какой-либо узел, поэтому они передается по значению. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 13:49 Большое спасибо! :)
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 26, 2014, 13:50 Спасибо! В данном случае - понятно. А если это класс Person, в котором: имя, фамилия, отчество и возраст? Это довольно маленький класс. Хороший показатель: есть ли оператор + (фактически он говорит что класс будет обыгрываться по значению). Др показатель - использует ли класс хоть какие-то распределения памяти - напр строки используют. Ну и редко но все же бывает что подача по значению выгодна задаче. ПримерКод В чем замысел программиста подавшего второй аргумент по значению? Название: Re: Как писать ООП программы? Отправлено: Hrundel от Февраль 26, 2014, 20:07 У меня в итоге только один вопрос: научился ли ТС писать ООП программы? ;D
Название: Re: Как писать ООП программы? Отправлено: BuRn от Февраль 26, 2014, 20:23 У меня в итоге только один вопрос: научился ли ТС писать ООП программы? ;D ИМХО тема из серии "Как скачать интернет"Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 26, 2014, 20:41 Пример Код В чем замысел программиста подавшего второй аргумент по значению? Замысел в том, чтобы не испортить матрицу-источник. Мне кажется, здесь ошибка (здесь нет матрицы) и нужно было так написать: Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 07:45 Я хочу реализовать свою идею с рисованием фигуры до рабочего состояния. И своими глазами увидеть почему нужно функцию draw() делать чисто виртуальной в базовом классе, и как её написать для каждого класса потомка. И какие ещё проблемы всплывут во время реализации.
Вот моя идея, на примере класса Rectangle: - В базовом абстрактном классе Shape, я реализовал хранение пар координат в динамическом массиве. Координаты точек рассчитываются во время создания объекта и сохраняются в массив. Точку можно получить по индексу: Код
В функции main() я создаю объект класса Viewer и "скармливаю" ему объекты с динамическим типом Rectangle. Я хочу чтобы объект класса Viewer хранил копии объектов Rectangle и др. для перерисовывания. Хранить копии объектов нужно для функции paintGL(), которая вызывается, когда объект нужно перерисовать. Но я пришёл к такой ситуации, что мне оказывается нужно хранить объекты класса Shape, а этого нельзя сделать, потому что нельзя создать объекты абстрактного класса. Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 27, 2014, 08:04 Зато можно хранить указатель или ссылку на абстрактный класс.
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 08:08 Да, но у меня в main объекты быстро удаляются:
Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 27, 2014, 08:24 Работайте с умными указателями, тогда объекты указателей в функции создания фигур быстро удаляться, а сами объекты фигур остануться жить, пока указатели на них будут храниться в списке viewer.
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 08:33 Работайте с умными указателями, тогда объекты указателей в функции создания фигур быстро удаляться, а сами объекты фигур остануться жить, пока указатели на них будут храниться в списке viewer. Огромное спасибо! Я теперь смогу изучить работу с умными указателями на практике :) P.S. Позже напишу о результатах. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 11:50 Посмотрите, пожалуйста, мой маленький демонстрационный пример. Корректно ли я работаю с умными указателями:
Output: Цитировать Name of the Shape: Rectangle Name of the Shape: Circle Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 27, 2014, 12:32 Код
Код
В функции main() я создаю объект класса Viewer и "скармливаю" ему объекты с динамическим типом Rectangle. Я хочу чтобы объект класса Viewer хранил копии объектов Rectangle и др. для перерисовывания. Хранить копии объектов нужно для функции paintGL(), которая вызывается, когда объект нужно перерисовать. Ну конечно бред собачий - но это неизбежно при любом самостоятельном проектировании :) "Хранить копии объектов" - не лезет ни в какие ворота. Простой. хороший и очень популярный способ - viewer знает контейнер УКАЗАТЕЛЕЙ на базовый класс Shape и может вызвать виртуальный draw для каждого из них. Тогда правда неясно что делает массив(ы) точек. Но этот подход - не единственный, а иногда и не лучший. Напр задача не просто рисовать OpenGL, но и кешировать данные рисования в карте (VBO). Тогда может ставить вопрос так: - каждая фигура умеет создавать свои "данные рисования" (напр массив точек) которые хранятся вьюером умеющим их отображать. Это конечно совсем не "копии объектов". Заметим что придется попотеть с такими данными для такого "простейшего" объекта как Circle. Да, и вот если бы у Вас был шейп Polygon - возможно и возникла бы идея метода Convert2Polygon. А так мало кода - много измышлений :) Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 27, 2014, 13:31 Посмотрите, пожалуйста, мой маленький демонстрационный пример. Корректно ли я работаю с умными указателями: Добавьте отладочный вывод в конструкторы и деструкторы фигур и все увидите. :)Учитесь проверять самостоятельно, придумывайте как что можно проверить, иначе вы всегда будете за кем то ходить и спрашивать правильно или нет. ;) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 14:19 Код
Код
Да, точно! Большое спасибо! :) может вызвать виртуальный draw для каждого из них. Почему-то все примеры с фигурами (для демонстрации полиморфизма) содержат чисто виртуальную функцию draw(). Но я до сих пор не могу понять, как это реализовать на простейшем примере, используя QGLWidget. Я вижу только один выход - каждый объект статического типа Shape хранит в себе массив точек. Заметим что придется попотеть с такими данными для такого "простейшего" объекта как Circle. Circle - это многоугольник с бессконечным количеством вершин. К примеру, можно ограничиться шестиугольником :) Да, и вот если бы у Вас был шейп Polygon - возможно и возникла бы идея метода Convert2Polygon. А так мало кода - много измышлений :) Polygon - это слишком сложно. Я не знаю, как считать площать многоугольника. Тут интеграл, наверное, нужен. Посмотрите, пожалуйста, мой маленький демонстрационный пример. Корректно ли я работаю с умными указателями: Добавьте отладочный вывод в конструкторы и деструкторы фигур и все увидите. :)Учитесь проверять самостоятельно, придумывайте как что можно проверить, иначе вы всегда будете за кем то ходить и спрашивать правильно или нет. ;) Ошибок там нет. Во всяком случае, компилируется и выводит результат. Я просто хотел убедиться, что правильно применил shared_ptr :) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 14:47 "Хранить копии объектов" - не лезет ни в какие ворота. Простой. хороший и очень популярный способ - viewer знает контейнер УКАЗАТЕЛЕЙ на базовый класс Shape Я боялся, что кто-нибудь удалит объекты и viewer крякнет. Я не знаю, как бы я выкрутился без shared_ptr Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 27, 2014, 14:49 Ура-а-а! Рисует! :D
(http://i7.pixs.ru/storage/3/2/8/138png_9115939_11042328.png) Скажите, пожалуйста, как можно развить ООП дальше в этом примере с фигурами? У меня есть идея сделать Rectangle шаблоном. Ведь для вывода на экран нужны целые значения и в тоже время хочется иметь возможность считать площадь в вещественном виде. Хотя... всё равно неявно из double в int преобразуется (для функций рисования). Просто для практики попробую. Нужно будет, наверное, ещё повороты (ориентацию под углом) как-то реализовать. main.cpp Код
viewer.h Код
viewer.cpp Код
rectangle.h Код
shape.h Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 27, 2014, 16:16 Скажите, пожалуйста, как можно развить ООП дальше в этом примере с фигурами? Пока все это напоминает дамскую прогулкуУ меня есть идея сделать Rectangle шаблоном. Цитировать Полторы мили пешком, назад в коляске Сделал аж Rectangle - ну вот и типа "освоил". А делать тот же Circle - та ну его, "мы устали". Код почистить тоже времени нет, тут же такие вкусные плюшечки ("умные" указатели и.т.п). Да и вообще, черновая работа не для нас, мы будем "обобщать" (с помощью шаблонов и др пакостей).Плохо, очень плохо :'( Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 27, 2014, 16:31 (с помощью шаблонов и др пакостей). Ну да, шаблоны вы тоже не осилили... :)Вы не знаете и половины языка, на котором пишете, вот это действительно: Плохо, очень плохо А человек только начал разбираться, у него все еще впереди. Хотя задачи он ставит себе очень синтетические, но не вы ли ему предложили этот идиотизм? ;) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 07:59 Igors, это неокончательный вариант кода, а всего лишь черновик. Я его ещё буду улучшать.
Сейчас разбираюсь с шаблонами. Начал переписывать и разбирать код из этого правила: http://www.e-reading.bz/chapter.php/1002058/108/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Вроде сначала всё было понятно, а теперь запутался и ошибки не знаю, как исправить. Если несложно, скомпилируйте, пожалуйста, у себя: Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 09:24 Я думаю, что проблема в следующем коде, потому что когда я его убираю в комминтарии, то всё работает.
Но я так и не могу понять, что не так в этом коде: Код
Название: Re: Как писать ООП программы? Отправлено: VPS от Февраль 28, 2014, 10:15 Сейчас разбираюсь с шаблонами. Начал переписывать и разбирать код из этого правила: http://www.e-reading.bz/chapter.php/1002058/108/Mayers_-_Effektivnoe_ispolzovanie_CPP.html Вроде сначала всё было понятно, а теперь запутался и ошибки не знаю, как исправить. Если несложно, скомпилируйте, пожалуйста, у себя Если у Вас весь код написан в одном файле, то Вы пытаетесь определить полную спецификацию класса раньше, чем шаблон. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 10:18 Если у Вас весь код написан в одном файле, то Вы пытаетесь определить полную спецификацию класса раньше, чем шаблон. Да, точно! Спасибо огромное! :) Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 10:50 Ну да, шаблоны вы тоже не осилили... :) Ну чего Вы склочничаете когда Вас никто не трогал? :) И чего оно Вас так волнует сколько я знаю? :) Вы не знаете и половины языка, на котором пишете, Igors, это неокончательный вариант кода, а всего лишь черновик. Я его ещё буду улучшать. Книга что Вы штудируете интересна, но обратите внимание на слова улучшить структуру. Так вот сначала надо уметь создать хоть какую-то структуру. Этого умения у Вас пока нет, зато охотно впитываете вещи которые, по существу, требуют механического запоминания - но не принятия своих решений. Пусть вещи эти совсем неплохи - но главного они не заменят. К сожалению, эта ситуация очень типична, часто смотрю текст - ни классов, ни ф-ционала, ничего по уму нет, "зато" шаблонов навернул с 3 короба. Типа "больше всякой всячины" = лучше, мол, "хорошо знает язык" :) :'(Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 11:38 И чего оно Вас так волнует сколько я знаю? Так вы же постоянно пытаетесь судить о том, что не знание: шаблоны, пространства имён, стандартная библиотека, и пытаетесь отговорить людей это изучать. :)Но, если вы это не осилили это не значит , что никто не осилить. В основной массе специалисты спокойно используют все возможности С++. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 12:34 Объяните, пожалуйста, почему n = 10?
(http://i6.pixs.ru/storage/5/5/4/139png_4134182_11052554.png) Проект: https://github.com/8Observer8/Shapes/tree/drawingShapes (https://github.com/8Observer8/Shapes/tree/drawingShapes) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 13:06 Всё, исправил ошибку: в меню выбрал Build -> Clean Project "Shapes" -> Build -> Rebuild Project "Shapes"
(http://i6.pixs.ru/storage/8/4/8/140png_3020937_11052848.png) Название: Re: Как писать ООП программы? Отправлено: VPS от Февраль 28, 2014, 13:25 Маленький комментарий к коду: вместо использования "new" при создании "std::shared_ptr", вроде как рекомендуют использовать "std::make_shared".
П.С.: только эта функция не позволяет задавать пользовательскую операцию удаления. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 18:14 И что, если клиент вызывает Circle::setRadius - продолжает рисоваться старый?
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 18:32 И что, если клиент вызывает Circle::setRadius - продолжает рисоваться старый? Новый должен рисоваться. Вот только почему-то компилятор ищет имя "setRadius" в базовом классе. Ошибка такая: Цитировать Shapes\main.cpp:31: error: 'class myShapes::Shape' has no member named 'setRadius' pc->setRadius(25.0); ^ На строке: pc->setRadius(25.0); Код
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 28, 2014, 18:40 Потому как базовый класс Shape не знает метода setRadius()
Название: Re: Как писать ООП программы? Отправлено: gil9red от Февраль 28, 2014, 18:43 Потому как базовый класс Shape не знает метода setRadius() И по логике, не обязан, ибо не у всех фигур есть радиус :)Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 18:48 Потому как базовый класс Shape не знает метода setRadius() То конечно хороший вопрос, но пусть сначала вынесет генерацию из конструктора и хоть как-то наладит взаимодействие классов. А то пока только песиков наводит.Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 28, 2014, 18:50 Пусть учится
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 18:54 Получается, что при передачи в функцию через указатель на базовый класс полиморфизм работает, а если в том же блоке, то нет? Непонятно...
Название: Re: Как писать ООП программы? Отправлено: Johnik от Февраль 28, 2014, 18:58 ...а если в том же блоке... что в том же блоке?Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 19:05 Я имею виду, что объявляем указатель на базовый класс и инициализируем его объектом производного:
Код
И это не работает. А если так же с функцией, то работает: Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 19:21 А если так же с функцией, то работает: Да ладно. ;)Попробуйте там вызвать setRadius. Если вы хотите пользоваться частным (не общим) функционалом производного класса, то придется приводить указатель к этому классу. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 19:50 Значит, я полиморфизм неправильно понял. Видимо, перепутал с ситуацией, когда в производном переопределяется функция с ключевым словом "virtual".
Статический полиморфизм (с шаблонами) пока в сторону. Нужно лучше динамический проработать. А как привести? Код
Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 19:53 А как привести? std::dynamic_pointer_cast<T>( ptr );И лучше сишные касты оставить для си. Название: Re: Как писать ООП программы? Отправлено: gil9red от Февраль 28, 2014, 20:02 А как привести? std::dynamic_pointer_cast<T>( ptr );И лучше сишные касты оставить для си. Цитировать Предпочитайте приведения в стиле C++ старому стилю. Их легче увидеть, и они более избирательны. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 20:05 Код
Агв, вероятно Shape может быть создана временно и уже нигде не хранится, будет удалена автоматычно после отрисовки. Если же программист не планировал этого то ему следовало ограничиться простым Код Не засоряя мозги ни себе ни людям. Принцип "кашу маслом не испортишь" в программировании неприменим Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 20:07 но ЗАЧЕМ программист так делал? Потому что программист использует shared_ptr. :)Если (допустим) я не в теме, то... нужно пойти подучиться.Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 20:15 А как привести? std::dynamic_pointer_cast<T>( ptr );И лучше сишные касты оставить для си. Огромное спасибо! Работает! Вот что-то радиус не меняет. :( Правило 27 :) (http://www.e-reading.bz/chapter.php/1002058/69/Mayers_-_Effektivnoe_ispolzovanie_CPP.html) Цитировать Предпочитайте приведения в стиле C++ старому стилю. Их легче увидеть, и они более избирательны. Спасибо! Я пропустил это правило. :) Не подряд читаю. А только если что-то нужно. Вот сейчас нужно, и надо прочитать :) Агв, вероятно Shape может быть создана временно и уже нигде не хранится, будет удалена автоматычно после отрисовки. Если же программист не планировал этого то ему следовало ограничиться простым Код Не засоряя мозги ни себе ни людям. Принцип "кашу маслом не испортишь" в программировании неприменим В моём viewer'e хранится массив указателей на внешние объекты. Пользователь может вызвать delete для внешних объектов. shared_ptr спасает тем, что в нём есть счётчик ссылок. Пока есть хоть одна ссылка на объект, то он не удалится. Viewer'у необходимо перерисовывать пока программа работает. Вот ситуация, когда объекты удалились до их показа: Код
Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 20:19 И лучше сишные касты оставить для си. Предпочитайте приведения в стиле C++ старому стилю. Их легче увидеть, и они более избирательны. Также очень популярное правило лишь по той причине что.. "его легко выучить" :) Ну правда, стоит лишь запомнить "С приведение = плохо. С++ приведение = хорошо" - и все (якобы) освоил :) В действительности "С приведение" с полным правом может считаться "expert mode" - все оно прекрасно сделает, вот только если неправильно - нет ошибки, ничего не скажет. Ну так ведь на то и "эксперт" :) Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 20:21 Вот что-то радиус не меняет. :( Так он и не будет. У вас весь просчет окружности происходит в конструкторе. Вам нудно вынести его в отдельный метод и вызывать его после любого изменения радиуса.Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 20:25 Вот что-то радиус не меняет. :( Так он и не будет. У вас весь просчет окружности происходит в конструкторе. Вам нудно вынести его в отдельный метод и вызывать его после любого изменения радиуса.А-а-а точно! :) Большущее спасибо! :) Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 20:26 Viewer'у необходимо перерисовывать пока программа работает. Вот ситуация, когда объекты удалились до их показа: И что, удаленные объекты все равно рисуются ???Ну хз, может в радиофизике "так надо" (др разумного объяснения не вижу) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 20:33 Нет конечно :)
Это пример плохого кода. Их можно удалить и после показа, тогда viewer'у тоже нечего будет рисовать. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 20:51 А с shared_ptr указатели не нужно удалять, и viewer'у это наруку :)
Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 21:04 А вот по поводу перерасчёта координат при изменении радиуса. Я должен очистить массив координат и заполнить поновой.
Может же возникнуть такая ситуация, что viewer узнает размер массива координат и начнёт считывать точки. А вот в это время пользователь изменит радиус. Массив координат очистится. И viewer обратится по неправильному индексу. Название: Re: Как писать ООП программы? Отправлено: Igors от Февраль 28, 2014, 21:09 А с shared_ptr указатели не нужно удалять, и viewer'у это наруку :) ??? Поясните идею. Вот допустим радиус Circle изменился - надо перерисовать сцену с учетом нового радиуса. Причем здесь удалять/не удалять? Ведь число рисуемых объектов никак не изменилосьНазвание: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 21:12 А с shared_ptr указатели не нужно удалять, и viewer'у это наруку :) ??? Поясните идею. Вот допустим радиус Circle изменился - надо перерисовать сцену с учетом нового радиуса. Причем здесь удалять/не удалять? Ведь число рисуемых объектов никак не изменилосьЯ не понял вопроса :) Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 21:37 Ну правда, стоит лишь запомнить "С приведение = плохо. С++ приведение = хорошо" - и все (якобы) освоил :) Вам нужно переставать смотреть видеокурсы "С++ за 5 дней". :)Вроде вы уже наскакивали на виртуальное наследование. В действительности "С приведение" с полным правом может считаться "expert mode" - все оно прекрасно сделает, вот только если неправильно - нет ошибки, ничего не скажет. Ну так ведь на то и "эксперт" :) А здесь можно тешить себя как угодно. Можете даже считать его "God mode". :)Название: Re: Как писать ООП программы? Отправлено: Old от Февраль 28, 2014, 21:39 Может же возникнуть такая ситуация, что viewer узнает размер массива координат и начнёт считывать точки. А вот в это время пользователь изменит радиус. Массив координат очистится. И viewer обратится по неправильному индексу. Такая ситуация возможна только, если программа использует несколько потоков. Но тут и средства будут другие.Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Февраль 28, 2014, 21:53 Может же возникнуть такая ситуация, что viewer узнает размер массива координат и начнёт считывать точки. А вот в это время пользователь изменит радиус. Массив координат очистится. И viewer обратится по неправильному индексу. Такая ситуация возможна только, если программа использует несколько потоков. Но тут и средства будут другие.Да, точно! Получается, что когда мы внутри функции отрисовки, то ничего другого выполняться не будет. И так же, когда координаты генерируем и в это время нужно перерисовать, то код отрисовки "будет ждать" пока не выполнится генерация координат. Название: Re: Как писать ООП программы? Отправлено: Johnik от Март 01, 2014, 00:13 Значит, я полиморфизм неправильно понял. Видимо, перепутал с ситуацией, когда в производном переопределяется функция с ключевым словом "virtual". Предлагаю пока оставить приведение типов в покое и проработать все без него, тем более оно тут пока и не нужно.Статический полиморфизм (с шаблонами) пока в сторону. Нужно лучше динамический проработать. А как привести? Код
Вообще стоит понять, где нужен полиморфизм, а где нет. Ваш код можно написать примерно так: Код: int main(int argc, char *argv[]) Название: Re: Как писать ООП программы? Отправлено: Old от Март 01, 2014, 03:19 Ваш код можно написать примерно так: Ну если цель только избавиться от приведения, то достаточно в коде ТС просто изменить тип указателя:Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 01, 2014, 07:41 std::shared_ptr<myShapes::Circle> pc(new myShapes::Circle(50.0)); myShapes::Circle pc(50.0); Эти два примера абсолютно эквивалентные. В первом - объект создаётся динамически (из кучи), во втором - статически (в стеке). Теперь я понял, что объекты не обязаны иметь статический тип Shape для передачи в функцию, которая принимает указатель на объект базового класса. Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 01, 2014, 07:54 Я понял, что в моём примере идеально подходят умные указатели (shared_ptr). Viewer, принимая указатели на внешние объекты, может быть спокоен, что объект действительно существует (кстати, должен ли он проверять непустой ли указатель?) Допустим, я решил не использовать умные указатели и единственный способ заставить viewer рисовать - это не удалять объекты выделенные из кучи. Если я точно знаю, что объектов будет не слишком много, то могу ли я себе позволить не удалять объекты выделенные динамически? Даже с умными указателями, объекты просуществуют столько же, как если не удалять с помощью delete. Вот так:
Код
Название: Re: Как писать ООП программы? Отправлено: Old от Март 01, 2014, 09:21 Я понял, что в моём примере идеально подходят умные указатели (shared_ptr). Как и для всего остального. :)(кстати, должен ли он проверять непустой ли указатель?) Конечно. Пользователь класса Viewer может легко передать пустой указатель, поэтому лучше всего проверять указатель при добавлении объекта в методе addForPainting.могу ли я себе позволить не удалять объекты выделенные динамически? Сможете, главное не забыть удалить их потом.Воспользуйтесь typedef'ами, с ними значительно понятней. Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 01, 2014, 09:30 Воспользуйтесь typedef'ами, с ними значительно понятней. Вот то, что нужно! Видно сразу силу пространств имём, умных указателей и typedef'ов :)могу ли я себе позволить не удалять объекты выделенные динамически? Сможете, главное не забыть удалить их потом.А где их тогда удалить в этом примере: Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 01, 2014, 09:36 Воспользуйтесь typedef'ами, с ними значительно понятней. Код
Уточнить имена нужно: Код
Название: Re: Как писать ООП программы? Отправлено: Old от Март 01, 2014, 09:53 А где их тогда удалить в этом примере: Например, в деструкторе Viewer.Название: Re: Как писать ООП программы? Отправлено: Old от Март 01, 2014, 09:54 Уточнить имена нужно: Мы же разрешили это пространство имен: Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 01, 2014, 10:03 Уточнить имена нужно: Мы же разрешили это пространство имен:Код
А да, извените, не заметил :) А где их тогда удалить в этом примере: Например, в деструкторе Viewer.Да, похоже, это правильный ответ. Но что плохого в том, что мы НЕ будем применять delete к объектам? В моём приложении объекты в любом случае живут до конца, хоть это умный указатель, хоть особождение в деструкторе Viewer. Ведь при завершении приложения вся память возвращается системе. Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 01, 2014, 14:14 Плюс shared_ptr ещё в том, что пользователю (класса Viewer) не нужно бояться, что viewer удалит объект через указатель :)
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 02, 2014, 08:12 Помогите, пожалуйста, разобраться почему не стирается старое изображение?
(http://i.pixs.ru/storage/2/1/8/142png_4847648_11075218.png) Когда я меняю радиус: main.cpp Код
Как в функции перерисовки стереть старое изображение? viewer.cpp Код
Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 02, 2014, 08:17 Вот весь проект: https://github.com/8Observer8/Shapes/tree/drawingShapes
Название: Re: Как писать ООП программы? Отправлено: Igors от Март 02, 2014, 08:25 Но что плохого в том, что мы НЕ будем применять delete к объектам? В моём приложении объекты в любом случае живут до конца, хоть это умный указатель, хоть особождение в деструкторе Viewer. Ведь при завершении приложения вся память возвращается системе. Так развивайте архитектуру, заводите класс "сцена", который будет хранить созданные объекты, загружать/выгружать их в файл и др. В этом и состоит основная работа: спроектировать хорошие классы, наладить их четкое взаимодействие. А лепить глобалы в main то так, "поменяйте мне подгузник" :) Название: Re: Как писать ООП программы? Отправлено: Igors от Март 02, 2014, 08:38 Помогите, пожалуйста, разобраться почему не стирается старое изображение? Circle::calcCoordinates должна сначала очистить вектор точек, а потом его заполнитьКак в функции перерисовки стереть старое изображение? По умолчанию машина рисования сама стирает все перед каждым новым paintНазвание: Re: Как писать ООП программы? Отправлено: 8Observer8 от Март 02, 2014, 09:00 Igors, спасибо огромное! Исправлю ошибки. Всё таки есть ещё куда развивать этот проектик :)
P.S. Я хочу чуть позже реализовать рисование в 3D. Мне кажется, что архитектура моего приложения несколько изменится. Как я понял в OpenGL все объекты состоят из треугольников и\или квадратов. Мои классы фигур будут хранить больше координат. Получается, что для круга мне нужно будет окружность задавать через координаты треугольников :-\ Название: Re: Как писать ООП программы? Отправлено: Igors от Март 02, 2014, 09:31 Всё таки есть ещё куда развивать этот проектик :) Поверьте, Вы его практически даже не начали :)P.S. Я хочу чуть позже реализовать рисование в 3D. Мне кажется, что архитектура моего приложения несколько изменится. Как я понял в OpenGL все объекты состоят из треугольников и\или квадратов. Мои классы фигур будут хранить больше координат. Получается, что для круга мне нужно будет окружность задавать через координаты треугольников :-\ Ладно, поговорим об архитектуре. Вот у Вас Circle имеет radius. На первый взгляд это не вызывает сомнений, ну как же круг без радиуса? Это же его "неотъемлемое" свойство. Однако большой круг или маленький - все равно "круг", форма-то (shape) одна. Теперь более конкретно: каждый раз, создавая Circle мы создаем и массив координат для него, а в перспективе этих данных еще больше. Создал юзер напр 1000 объектов - и у нас 1000 массивов (вероятно совершенно одинаковых). А ведь легко сделать умнее: хранить один "эталонный" массив для радиуса = 1, и в момент рисования скалить его до нужного. Да, но тогда выходит сам shape еще недостаточен, нужен еще класс (вот он и будет хранить радиус), а какой? Впрочем у Вас и так shape недостаточен, позицию он не хранит, пока задаете от фонаря.Вообще программист всегда хорошо знает чего он хочет от класса, что класс должен уметь и чего нет (последнее часто более важно). Записать это словами в файл - совсем не вредно. А Вы заболтили все проектирование и бегаете с какой-то бижутерией/аксессуарами :) Название: Re: Как писать ООП программы? Отправлено: 8Observer8 от Апрель 03, 2014, 13:42 Многие пишут, что это самая лучшая книга по ООП (объектно-ориентированному программированию и проектированию). Я только начал. Написано просто. Может кто-то ещё не читал и кому-то эта информация пригодится.
Приёмы объектно-ориентированного проектирования. Паттерны проектирования Год: 2010 Автор: Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Язык: Русский Количество страниц: 366 Ссылка: http://rutracker.org/forum/viewtopic.php?t=3193196 Описание: В предлагаемой книге описываются простые и изящные решения типичных задач, возникающих в объектно-ориентированном проектировании. Паттерны появились потому, что многие разработчики искали пути повышения гибкости и степени повторного использования своих программ. Найденные решения воплощены в краткой и легко применимой на практике форме. Авторы излагают принципы использования паттернов проектирования и приводят их каталог. Таким образом, книга одновременно решает две задачи. Во-первых, здесь демонстрируется роль паттернов в создании архитектуры сложных систем. Во-вторых, применяя содержащиеся в справочнике паттерны, проектировщик сможет с легкостью разрабатывать собственные приложения. Издание предназначено как для профессиональных разработчиков, так и для программистов, осваивающих объектно-ориентированное проектирование. |