реклама на сайте
подробности

 
 
> Как писать на С++ при создание приложений под ARM, Примеры
Hellper
сообщение Jun 18 2011, 20:15
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 13-08-07
Из: Санкт-Петербург
Пользователь №: 29 745



Посоветуйте примеры использование С++ при создание программ под архитектуру ARM микроконтроллеров. Такие примеры, чтобы показывали удобство и силу использование ООП, и тянуло сразу садится, вникать и кодить.
спасибо
пс желательно под компилятор от keil-а или gcc

ПС извините за дублирование. неполадки связи.


--------------------
Go to the top of the page
 
+Quote Post
13 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 99)
Danis
сообщение Jun 18 2011, 20:21
Сообщение #2


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(Hellper @ Jun 19 2011, 00:15) *
Посоветуйте примеры использование С++ при создание программ под архитектуру ARM микроконтроллеров. Такие примеры, чтобы показывали удобство и силу использование ООП, и тянуло сразу садится, вникать и кодить.


Довольно непонятная (по крайней мери для меня) привязка ООП к ARM архитектуре. Вам примеры программ c использованием ООП нужны?


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 18 2011, 20:36
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (Hellper @ Jun 18 2011, 23:15) *
тянуло сразу садится, вникать и кодить.

Я бы в летчики пошел,
пусть меня научат.
Наливаю в бак бензин,
завожу пропеллер.
"В небеса, мотор, вези,
чтобы птицы пели".


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 18 2011, 20:53
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Danis @ Jun 19 2011, 00:21) *
Довольно непонятная (по крайней мери для меня) привязка ООП к ARM архитектуре.

+1.
C++ и ARM - вещи ортогональные. Точно такой же C++ позволяет писать программы и для x86, MIPS, AVR32 и т.д. без оглядки на набор инструкций процессора. Отсюда и недоумение.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 19 2011, 03:03
Сообщение #5


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (Hellper @ Jun 19 2011, 05:15) *
и тянуло сразу садится, вникать и кодить.

Мне кажется, что насилие здесь, как и во многих других ситуациях, неприемлемо.


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
gladov
сообщение Jun 20 2011, 04:34
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687



Цитата(Hellper @ Jun 19 2011, 00:15) *
Посоветуйте примеры использование С++ при создание программ под архитектуру ARM микроконтроллеров. Такие примеры, чтобы показывали удобство и силу использование ООП, и тянуло сразу садится, вникать и кодить.
спасибо
пс желательно под компилятор от keil-а или gcc

ПС извините за дублирование. неполадки связи.


С++ плохо подходит для ARM. Серьезно! Появляются накладняки на требуемую память, ООП пытается тянуть за собой в проект использование динамической памяти и еще много всяких неудобств. Зачем это Вам?

А если серьезно, то я сам пишу под АРМ на С++, но чтобы к этому прийти, надо сначала понять что такое ООП вообще, зачем оно нужно, почему иногда оно удобнее, и лишь потом, если придет просветление (для ускорения процесса можно почитать, например, про шаблоны ООП) можно пытаться прикрутить объекты к АРМам.
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 20 2011, 07:32
Сообщение #7


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(gladov @ Jun 20 2011, 11:34) *
С++ плохо подходит для ARM. Серьезно! Появляются накладняки на требуемую память, ООП пытается тянуть за собой в проект использование динамической памяти и еще много всяких неудобств. Зачем это Вам?

А если серьезно, то я сам пишу под АРМ на С++, но чтобы к этому прийти, надо сначала понять что такое ООП вообще, зачем оно нужно, почему иногда оно удобнее, и лишь потом, если придет просветление (для ускорения процесса можно почитать, например, про шаблоны ООП) можно пытаться прикрутить объекты к АРМам.

Два, нет - три вопроса:
  1. Какое отношение имеет ООП к динамической памяти?
  2. Почему вы ставите знак равенства между С++ и ООП?
  3. Причём тут вообще паттерны проектирования? Какое они имеют отношение к ЯП С++?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 20 2011, 08:07
Сообщение #8


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (gladov @ Jun 20 2011, 13:34) *
и еще много всяких неудобств

Можно подробнее?
Пишу только на Си++ для AVR (8 бит) да еще и в контексте ОС scmRTOS (спасибо ее создателям, а особенно уважаемому dxp!). Честно говоря, удобства типа:
1. Наследования объектов.
2. Перегрузки функций.
3. Операторов ++ и -- (если не ошибаюсь, они появились именно в Си++).
4. Более строгого контроля типов данных,
покрывают дополнительные расходы на память. Все сказанное субъективно, т.е. лично мое.


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 20 2011, 09:54
Сообщение #9


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(haker_fox @ Jun 20 2011, 12:07) *
3. Операторов ++ и -- (если не ошибаюсь, они появились именно в Си++).

Если перегруженные, то да.
А обычные целочисленные и в обычном си были.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
klen
сообщение Jun 20 2011, 10:45
Сообщение #10


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



Цитата(gladov @ Jun 20 2011, 08:34) *
С++ плохо подходит для ARM. Серьезно! Появляются накладняки на требуемую память, ООП пытается тянуть за собой в проект использование динамической памяти и еще много всяких неудобств. Зачем это Вам?
А если серьезно, то я сам пишу под АРМ на С++, но чтобы к этому прийти, надо сначала понять что такое ООП вообще, зачем оно нужно, почему иногда оно удобнее, и лишь потом, если придет просветление (для ускорения процесса можно почитать, например, про шаблоны ООП) можно пытаться прикрутить объекты к АРМам.


ужосс .. Вы меня извините, но это чуш. Вы хоть раз в ассемблер заглядывали из под компиллера выходящий? если магнитофоном забивать гвозди - то да С++ для АRМ не подходит, а в остальных даже очень. у меня почемуто в сложных проектах наоборот кода стало меньше - улучшилась структура кода.

более того, проведу натянутую аналогию - никто не мешает использовать базовый функционал языка С++ без фанатских расширений - тогда он будет похож на С со структурами. но вы еще в эти структуры поведение в виде методов занесете + конструкторы. а код будет АПСАЛЮТНО!! такой же как если бы Вы на С написали.

с утверждением '"..надо сначала понять что такое ООП вообще, зачем оно нужно" - трудно несогласится, тока вот уровень 'понимания материала' вызывает вопросы

PS. - я не люблю кошек.
- ты просто не у мееш их готовить!
Go to the top of the page
 
+Quote Post
Axel
сообщение Jun 20 2011, 11:22
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 480
Регистрация: 21-11-04
Пользователь №: 1 188



Цитата(gladov @ Jun 20 2011, 07:34) *
...прикрутить объекты к АРМам.

Сразу напрашивается развитие темы: прикрутить ботинки к носкам, трусы к ... ну и так далее. ООП и АРМы - давно и независимо существующие сушности, способные тем не менее прекрасно уживаться в рамках конкретного проекта и вобщем-то без какого-либо "прикручивания". А трудности постижения духа и сути ООП ИМХО несколько преувеличены.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jun 20 2011, 11:35
Сообщение #12


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(Hellper @ Jun 19 2011, 00:15) *
Посоветуйте примеры использование С++ при создание программ под архитектуру ARM микроконтроллеров.
Так scmRTOS и посмотрите.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 20 2011, 12:15
Сообщение #13


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



ТС, позвольте не большой, скромный вопрос к Вам. Зачем Вам С++ и ООП?
Есть какая то конкретная задача, либо просто нужно «войти» в тему ООП, пока мне не понятно. Расскажите, попробую Вам помочь, скину примеры кода в «личку» какие попросите.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
GDI
сообщение Jun 20 2011, 13:11
Сообщение #14


Профессионал
*****

Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008



ringbuffer-dlya-embedded - пример кода, и даже не один, в камментах еще примеры есть.


--------------------
http://www.embedders.org Блоги разработчиков электроники.
Go to the top of the page
 
+Quote Post
Hellper
сообщение Jun 20 2011, 16:05
Сообщение #15


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 13-08-07
Из: Санкт-Петербург
Пользователь №: 29 745



Цитата(GDI @ Jun 20 2011, 17:11) *
ringbuffer-dlya-embedded - пример кода, и даже не один, в камментах еще примеры есть.


спасибо


--------------------
Go to the top of the page
 
+Quote Post
gladov
сообщение Jun 21 2011, 06:40
Сообщение #16


Частый гость
**

Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687



Цитата(dxp @ Jun 20 2011, 11:32) *
Два, нет - три вопроса:
  1. Какое отношение имеет ООП к динамической памяти?
  2. Почему вы ставите знак равенства между С++ и ООП?
  3. Причём тут вообще паттерны проектирования? Какое они имеют отношение к ЯП С++?


Начну со второго: да, возможно я излишне строго приравнял C++ и ООП. Это конечно не так, я немного не то имел ввиду. Конечно, C++ дает нам много вкусностей помимо "классического" ООП. Но, согласитесь, основные достоинства языка С++ заключаются в его возможности писать ОО-код. Именно поэтому я не приравнял С++ и ООП, но поставил их совсем рядом и позволил себе в первом посте сместить акцент в сторону ООП.
Отношение ООП к динамике? Да никакого! Но во многих учебниках, а также в ВУЗах, преподается ООП (позвольте я все же буду тут писать про ООП, коль уж мой первый пост был де-факто про него) в тесной свзяке с динамической памятью, ибо так легче показать виртуализацию и полиморфизм. Поэтому и написал, что "ООП пытается тянуть за собой ....". Согласитесь, многие вещи удобнее реализовываются если использовать динамику? Однако этого лучше не делать, либо делать с умом, понимая механизмы и возможные последствия.
Паттерны? А разве плохо знать о них? А к С++ они имеют прямое отношение: их можно реализовать используя С++, а вот на С сделать то же самое гораздо сложнее.
Go to the top of the page
 
+Quote Post
brag
сообщение Jun 21 2011, 08:09
Сообщение #17


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Да, стоит сделать new, как c++ тянет библиотечный malloc и еще иногда кучу всякого несовместимого. а если у вас защищенная ось, у каждого треда свой stack,data,heap, то и malloc должен быть свой(если есть, у меня нету heap пока,не нужно пока), и попробуй ему обясни куда надо класть данные. и еще многие вкусности c++ тянут...мотому я пишу C.
Хотя для графики(всяких там менюшек) лучше(удобнее) c++, мож буду юзать, когда нужно будет сложную графическую оболочку делать
а ООП и на C кодится, (какая разница, написать obj.func(x) или чтото типа class_func(&obj,x) ?), хоть и далеко ему до наворотов C++
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 21 2011, 08:47
Сообщение #18


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



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

Цитата(gladov @ Jun 21 2011, 13:40) *
Начну со второго: да, возможно я излишне строго приравнял C++ и ООП. Это конечно не так, я немного не то имел ввиду. Конечно, C++ дает нам много вкусностей помимо "классического" ООП. Но, согласитесь, основные достоинства языка С++ заключаются в его возможности писать ОО-код. Именно поэтому я не приравнял С++ и ООП, но поставил их совсем рядом и позволил себе в первом посте сместить акцент в сторону ООП.

Давайте наведём ясность с терминами, в частности с ООП. ООП - объектно-ориентированное программирование, в основе которого лежит описание программы в виде иерархий наследуемых объектов с виртуальными функциями (кои являются методами), с возможностью переопределять поведение методов на любом уровне иерархии. Т.е. если я просто определяю некий класс со своим представлением (данными) и интерфейсом (открытыми функциями-членами), объявляю объект[ы] этого класса и использую его[их] в программе - то это получается не ООП. Тут нет ни иерархий, ни наследования, ни методов (виртуальных функций). И даже если было бы и наследование, но без виртуальных функций, то и это было бы не ООП - т.к. ключевым свойством ООП является динамический полиморфизм - т.е. подмена поведения метода в наследнике на рантайме, а само по себе наследование этого не даёт.

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

Каждая парадигма имеет свои сильные и слабые стороны, и применять их все три надо к месту. С++ все эти три парадигмы поддерживает одинаково хорошо. И ни одна из них не порождает сколько-нибудь заметных накладных расходов в программе, чтобы их нельзя было использовать даже на 8-битных малышах, не говоря уже об АРМах. Где уместен С, там уместен и С++.

Цитата(gladov @ Jun 21 2011, 13:40) *
Отношение ООП к динамике? Да никакого! Но во многих учебниках, а также в ВУЗах, преподается ООП (позвольте я все же буду тут писать про ООП, коль уж мой первый пост был де-факто про него) в тесной свзяке с динамической памятью, ибо так легче показать виртуализацию и полиморфизм.

Совершенно нет. Никакого абсолютно отношения виртуальные функции и полиморфизм не имеют к работе со свободной памятью. Это полностью ортогональные вещи. Механизм виртуальных функций в С++ строится на таблицах указателей на функции - это вполне обычный механизм, хорошо известный ещё из языка С. Разница в том, что в С эти таблицы создавать, инициализировать адресами функций приходится вручную, в С++ этим занимается компилятор. Когда вы пишете код с таблицами указателей на функции на С, вам же не приходит в голову их размещать, в обязательном порядке вызывая malloc() - эти таблицы вполне нормально живут в статической памяти (да хоть в стеке, если время жизни таблицы достаточно для обслуживания кода, её использующего).

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

Цитата(gladov @ Jun 21 2011, 13:40) *
Поэтому и написал, что "ООП пытается тянуть за собой ....". Согласитесь, многие вещи удобнее реализовываются если использовать динамику?

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

В программах для РС, где присутствует GUI, это обычная практика - создавать объекты с помощью оператора new, т.к. GUI сам по себе динамичен - окна появляются и закрываются, действия пользователя на этапе написания программы не известны. Учитывая, что операция создания объекта в свободной памяти на РС не очень дорогая, этот подход широко применяется там и для других потребностей. Но и там злоупотреблять этим ни к чему. И недаром тов. Александреску даже разработал специальный быстрый менеджер памяти для использования его с небольшими объектами (он подробно описан в его книжке "Modern C++ design").

Цитата(gladov @ Jun 21 2011, 13:40) *
Паттерны? А разве плохо знать о них? А к С++ они имеют прямое отношение: их можно реализовать используя С++, а вот на С сделать то же самое гораздо сложнее.

Знать о них не плохо. Только это, вообще-то, приёмы проектирования, и реализовываться они могут на многих языках, а не только на С++. И уж нет никаких особы предпосылок к тому, чтобы считать их непригодными для реализации в embedded системах, в частности на ARM. Например, паттерн Singleton очень хорошо реализуется не то, что на ARM, но даже на AVR, и мы давно и широко его применяем.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2011, 09:21
Сообщение #19


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(dxp @ Jun 21 2011, 12:47) *
Если вы посчитали, что уже использование классов - это ООП, то это ошибочное суждение. С++ - гибридный язык программирования. Он в явном виде поддерживает три парадигмы:
  1. Процедурую, когда программист разбивает код на функции (процедуры) и строит программу как совокупность вызовов процедур (точно как в традиционном С).
  2. Объектную, когда программист размещает код в компактных объектах, скрывая детали реализации с помощью инкапсуляции и абстракции и определяя интерфейс для взаимодействия объектов с внешним (для объекта) миром, а программу, строит определяя взаимодействия объектов между собой и с другими программными сущностями.
  3. Объектно-ориентированную, когда код строится в виде иерархий полиморфных классов (см выше).

Спасибо за обзор. Лично для меня он оказался весьма полезным и своевременным.
Оказывается, я обычно реализую подход №2 ("объектный"), средствами языка Си: разделение интерфейса и реализации - module.h и module.c, сокрытие данных и служебных функций - ключевое слово static.
В связи с этим вопрос: не могли бы Вы привести примеры микроконтроллерных задач, в которых "объектно-ориентированный" подход даёт ощутимые преимущества?
Go to the top of the page
 
+Quote Post
brag
сообщение Jun 21 2011, 09:33
Сообщение #20


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



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

Цитата
В связи с этим вопрос: не могли бы Вы привести примеры микроконтроллерных задач, в которых "объектно-ориентированный" подход даёт ощутимые преимущества?

пример - графический юзверь-интерфейс. я какраз щас задачку ставить буду, где сложный gui, все на том же cortex-m3, QT там не пойдет, прийдется писать свой, тут и применю с++, посему и залез в эти темку sm.gif
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2011, 09:39
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(brag @ Jun 21 2011, 13:33) *
пример - графический юзверь-интерфейс. я какраз щас задачку ставить буду, где сложный gui, все на том же cortex-m3, QT там не пойдет, прийдется писать свой, тут и применю с++, посему и залез в эти темку sm.gif

При всём уважении, это голословное утверждение. Делал GUI (насколько сложный - тут мнения в любом случае разойдутся) именно "объектным" способом, никакой тяги к "полиморфизму" не ощутил.
Отсюда и вопрос. Хотелось бы с обоснованием, где именно полиморфизм реально помогает.
Go to the top of the page
 
+Quote Post
Axel
сообщение Jun 21 2011, 10:14
Сообщение #22


Местный
***

Группа: Свой
Сообщений: 480
Регистрация: 21-11-04
Пользователь №: 1 188



Цитата(scifi @ Jun 21 2011, 12:39) *
...где именно полиморфизм реально помогает.

Из практики: измерительная система, реализующая несколько различных измерений параметров одного объекта. Количество и последовательность измерений определяются пользователем. Оказалось удобным сделать классы конкретных измерений производными от общего базового виртуального класса. Структура программы получилась независимой от деталей (и изменений) каждой конкретной технологии.
Go to the top of the page
 
+Quote Post
brag
сообщение Jun 21 2011, 10:30
Сообщение #23


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
При всём уважении, это голословное утверждение. Делал GUI (насколько сложный - тут мнения в любом случае разойдутся) именно "объектным" способом, никакой тяги к "полиморфизму" не ощутил.

тут не полиморфизм, тут иерархия классов, а это уже ооп, а не оп. хотя и полиморфизм хорошо подходит.
покрасить кнопочку в синий цвет и покрасить окошко в синий цвет - совершенно разные процедуры, хотя их можно обьеденить в один метод "покрасить виджет"
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 21 2011, 11:58
Сообщение #24


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(scifi @ Jun 21 2011, 16:39) *
При всём уважении, это голословное утверждение. Делал GUI (насколько сложный - тут мнения в любом случае разойдутся) именно "объектным" способом, никакой тяги к "полиморфизму" не ощутил.
Отсюда и вопрос. Хотелось бы с обоснованием, где именно полиморфизм реально помогает.

Это вы зря - GUI, как раз, то место, где ООП рулит в полный рост. Не знаю, как у вас было организовано, но типовая схема такая: все объекты GUI являются членами иерархии классов, где в базовых классах объявляются методы (т.е. виртуальные функции), назначение которых выполнять действия, сходные по назначению, но разные по реализации. Например, у нас есть объекты: главное меню, выпадающее/всплывающее меню, пункт меню, графическая кнопка, строка состояния и т.п., а так же есть органы управления прибором - несколько кнопок или небольшая [плёночная] клавиатура. Нам нужно организовать управление всем ворохом графических объектов, но сделать это как-то единообразно. К примеру, нужно обрабатывать кнопку Right (перемещение вправо). Для этого мы в базовом классе иерархии объявляем виртуальную (если в самом базовом, то кошерно её объявлять чисто виртуальной - pure virtual) функцю void right(). И во всех производных классах, где это необходимо, эта функция переопределяется, чтобы получить для каждого класса своё поведение.

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

Так вот, код для реализации этого будет до безобразия прост:
Код
    TWidget *focus; // указатель на активный графический элемент (виджет)

   ...

    focus = ...;   //  focus присваивается адрес графического элемента - как правило это присваивание происходит
                      // внутри методов самих виджетов

   ...

    if( is_key_clicked(GUI::KEY_RIGHT)
    {
        focus->right();
    }

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

Таким образом, достаточно написать не очень обширный код, где будет просто организован вызов одной (!) функции на каждый орган управления. А всё разнообразие поведения графических объектов уже будет реализовываться уже путём определения самих этих объектов. При такой схеме есть чёткое разделение назначения действия от его реализации, можно без труда добавлять новые виджеты, можно без страха и геморроя менять поведение существующих. И работает это эффективно и безошибочно.

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

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

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 21 2011, 13:27
Сообщение #25


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



dxp, как у вас терпения хватает писать такие длинные посты? wink.gif Думаю, это будет отличным стимулом и введение в ООП, многих эмбедеров форума. Недаром говорят, «Новосибирск - город математиков и программистов»
Во общем респект и уважуха!!!

P.S. может в контексте этой темы и ваших постов Страуструпа выложить?


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2011, 14:37
Сообщение #26


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(dxp @ Jun 21 2011, 15:58) *
В общем, в любом приложении, где есть общие по назначению, но разные по исполнению действия, уместно применять ООП - динамический полиморфизм отлично ложится на реализацию такой задачи.

Другими словами, средства полиморфизма из Си++ могут быть оправданы там, где на Си нужно было бы вводить "поле типа" или массив указателей на функции.
Неудивительно, что у меня нет к этому тяги: в моих задачах это редко встречается :-)
Ещё раз, спасибо за развёрнутое объяснение.
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 21 2011, 15:55
Сообщение #27


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(scifi @ Jun 21 2011, 17:37) *
Другими словами, средства полиморфизма из Си++ могут быть оправданы там, где на Си нужно было бы вводить "поле типа" или массив указателей на функции.


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


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
brag
сообщение Jun 21 2011, 22:18
Сообщение #28


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



dxp, спасибо большое за обзорчик, вроде все и так понятно, но очень удобно, когда все собрано в кучке. распечатаю себе, как шпаргалку/краткое пособие wink.gif
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 22 2011, 01:05
Сообщение #29


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



dxp, спасибо за шикарные ответы!!! disco.gif
Не моголи бы Вы подсказать, по какой литературе обучались? Или это опыт?
Спасибо!


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jun 22 2011, 04:57
Сообщение #30


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Расказ про ООП конечно увлекательный, но стоит учитывать, что как только вы вылезете за область применения, описанную dxp (наследование от интерфейса и поточная обработка), то тут же вся система станет крайне неустойчивой. Конкретно: множественное наследование сразу ставит крест на проекте, перегрузка функций и операторов приводит к очень хитрым багам, развесистая иерархия наследования приводит к хрупкости системы - очень высокая связность элементов... Использование паттернов не имеет отношения к С++, но в микроконтроллерах не имеет особого смысла. Куда можно в AVR засунуть синглтон?! Использование шаблонов С++ сильно тормозит компиляцию и плохо контролируется по расходу памяти.
В общем, это неправда, что С++ оправдан везде, где оправдан С.
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2011, 06:29
Сообщение #31


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 22 2011, 06:38
Сообщение #32


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(andrewlekar @ Jun 22 2011, 08:57) *
Использование шаблонов С++ сильно тормозит компиляцию

Вместо двух секунд аж все десять! biggrin.gif
Цитата
Не моголи бы Вы подсказать, по какой литературе обучались?

Ну как минимум ссылка на Александреску уже висит sm.gif


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2011, 06:40
Сообщение #33


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(andrewlekar @ Jun 22 2011, 11:57) *
(наследование от интерфейса и поточная обработка), то тут же вся система станет крайне неустойчивой.
Почему? В чём причины неустойчивости?

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
Конкретно: множественное наследование сразу ставит крест на проекте,

Поясните? И причём тут множественное наследование? О нём вообще ни слова не было сказано.

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
перегрузка функций и операторов приводит к очень хитрым багам,

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

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
развесистая иерархия наследования приводит к хрупкости системы - очень высокая связность элементов...

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

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
Использование паттернов не имеет отношения к С++, но в микроконтроллерах не имеет особого смысла. Куда можно в AVR засунуть синглтон?!

Да как обычно - чтобы избавиться от зависимости порядка создания объектов при раздельной компиляции файлов проекта. Затраты на него копеечные.

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
Использование шаблонов С++ сильно тормозит компиляцию

Да, несколько секунд лишних, обычно, приходится потратить. sm.gif

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
и плохо контролируется по расходу памяти.

Это только если использовать бездумно и не представлять себе, во что выливается та или иная языковая конструкция. На сях тоже можно начать бездумно маллоки метать направо и налево, и будет "плохо контролируемый расход памяти".

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
В общем, это неправда, что С++ оправдан везде, где оправдан С.

Технически с точки зрения эффективности везде. А то, что голову надо включать, так это универсальное правило для любого ЯП. Единственное, с чем соглашусь, что С++ требует больше времени на изучение в силу много большего разнообразия и сложности самого языка. Это его единственный объективный недостаток перед С.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 06:53
Сообщение #34


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(andrewlekar @ Jun 22 2011, 08:57) *
В общем, это неправда, что С++ оправдан везде, где оправдан С.


Не согласен категорически, во всяком случае, C++ в программировании можно использовать и «ограничено», не зарываясь в тонкости ООП, при этом не платишь за то, что не используешь.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2011, 07:37
Сообщение #35


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(haker_fox @ Jun 22 2011, 08:05) *
Не моголи бы Вы подсказать, по какой литературе обучались? Или это опыт?

В основном по Страуструпу. Если есть реальный интерес к С++, то обязательно нужно прочитать его книжку "Дизайн и эволюция С++", она хоть и не техническая по языку, но зато из её прочтения куда лучше становятся понятны концепции языка, причинно-следственные связи, почему сделано так или иначе, а не иным способом. Очень полезное чтиво для понимания философии С++. Книжка, кстати, небольшая и читается очень легко.

Ну, и кореша есть, которые в плюсах "батонят" (как один из них выражается), особенно один, по сравнению с которым я просто мальчик в коротких штанишках. В общем, есть на кого равняться. sm.gif Ну, и опыт тоже, без опыта реальной работы, конечно, ничего не бывает, это как у всех.

На самом деле уровень проблем, который мы тут подняли, это в среде профессиональных программистов просто "асфальтированное шоссе", ко которому ехать легко и просто, это обычные штатные вещи, можно сказать тривиальные для них. Просто в embedded области в силу того, что С++ ещё только занимает позиции, и эти понятия, приёмы и средства языка идут в новинку. Но это и хорошо - то, что профессиональным РС программерам кажется рутиной и скукотой, для нас является прикольными фишками, которые вызывают искренний интерес и мотивируют работу. Второй момент: для нас это всё близко к железу, когда embedded программист пишет код, он всегда представляет, во что выльется реализация (если он хороший программист, конечно), поэтому чёткое понимание связи кода на С++ и его аппаратной реализации тоже пробуждает интерес. РС программисту в этом смысле хуже - от него реализация сидит слишком далеко. Кроме того, эффективное написание программ для настольных машин давно требует использования какого-нить развитого фреймворка, и программист оказывается заключённым в определённые рамки, выйти за которые он по сути не может - иначе сразу потеряет эффективность работы. Embedded программист в значительной степени свободен от этого, что предоставляет куда большие возможности для творчества. А именно творческое начало в любой работе делает эту работу интересной и желанной. Вот как-то так.

Цитата(Danis @ Jun 21 2011, 20:27) *
P.S. может в контексте этой темы и ваших постов Страуструпа выложить?

В смысле? Книжку его выложить или что?

Цитата(scifi @ Jun 21 2011, 21:37) *
Другими словами, средства полиморфизма из Си++ могут быть оправданы там, где на Си нужно было бы вводить "поле типа" или массив указателей на функции.
Неудивительно, что у меня нет к этому тяги: в моих задачах это редко встречается :-)

Ну, это ведь от целей зависит. И конечно, можно результат получать разными способами. Когда я ещё находился в процессе изучения С, был период, когда конструкции языка типа операторов if/for/while/switch уже были уверенно освоены, а концепция указателей на функции ещё не была - там один синтаксис выражения, задающего массив указателей на функции, просто пугал своей замороченностью и сложностью. И когда нужно было вызывать функции по условию, то городился switch, в котором перебором вызывался нужный код. Когда прогресс достиг и понимания концепции указателей на функции и возникла привычка к разбору кода "изнутри-наружу" в выражениях, то массивы указателей на функции стали применяться широчайшим образом для решения тех же задач, которые до этого решались исключительно с помощью операторов ветвления. Т.ч. возможно стоит пересмотреть существующие стереотипы, может это оказаться и не напрасным.

Цитата(Danis @ Jun 21 2011, 22:55) *
Маленько не так. Полиформизм дает возможность создавать множественные определения для операций и функций, что более абстрагирует программы. Конкретное определение, которое будет использоваться, зависит от задачи. В результате в крупном проекте коэффициент повторного использования кода возрастает. Си, к сожалению такой возможности не предоставляет.

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

* * *


Кстати, вспомнил ещё пример, где рулит ООП. Реально используется в текущем проекте. Уже как-то собирался выложить реализацию (правда, с другим акцентом), но всё руки не доходили. Раз уж тут пошло обсуждение, то пусть будет до кучи.

Речь идёт о передаче сообщений. Есть программа, в которой в разных её местах возникают события и нужно их как-то передавать на обработку. Причём, нужно сделать так, чтобы при необходимости добавить новый тип сообщения не нужно было перелопачивать существующий код. Иными словами, нужно, чтобы та часть программы, к которой попадает сообщение, как-то сама распознавала тип объекта-сообщения и обрабатывала его, если сообщение предназначено для неё, и игнорировала в противном случае. При этом и создание типов (классов) сообщений, и их посылка, и их приём были простыми и прозрачными для пользователя. Это чем-то похоже на технологию RTTI (Run Time Type Identification), поддерживаемую С++ и реализуемую на основе dynamic_cast<>, но в RTTI является довольно "тяжёлым" механизмом и не очень катит в embedded (к слову, не все компиляторы для МК и поддерживают это).

По организации. Данный пример взят из рабочего проекта, где есть небольшой самописный GUI, но сам принцип передачи сообщений, в общем, не зависит от того, где это применяется, и может быть обобщен на другие задачи. В данном примере есть иерархия классов, где заглавный абстрактный базовый класс выглядит следующим образом:
Код
    //--------------------------------------------------------------------------
    class TObject
    {
    public:
        virtual void on_message(TBaseMsgWrapper *msg_wrp) = 0;

    };
    //--------------------------------------------------------------------------

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

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

В общем, нужно, чтобы был простой и эффективный механизм генерации служебной информации, обозначающей тип сообщения, и эффективное средство проверки типа сообщения. В результате нам с корешем (он, кстати, тоже на элхе появляется под ником mikeT) удалось родить следующее (включение заголовочных файлов скипнуто):
Код
//------------------------------------------------------------------------------
inline uint16_t generate_id() { static uint16_t id; return ++id; }

class TBaseMsgWrapper
{
public:
    virtual uint16_t get_id() = 0;
};

template<typename T> class msg_wrapper : public TBaseMsgWrapper
{
public:
    msg_wrapper(T *msg) : body(msg), TBaseMsgWrapper() { }
    
    static  uint16_t get_class_id() { static const uint16_t id = generate_id(); return id; }
    virtual uint16_t get_id()       { return get_class_id(); }
    
    T *get_msg() const { return body; }
    
private:
    T *body;
};

template<typename T> T *check_msg(TBaseMsgWrapper *msg_wrp)
{
    if( msg_wrp->get_id() == msg_wrapper<T>::get_class_id() )
    {
        return (static_cast<msg_wrapper<T> *>(msg_wrp))->get_msg();
    }
    else
    {    
        return 0;
    }
}

template<typename T> bool send_message(T *msg, gui::TObject *dst)
{
    msg_wrapper<T> msg_wrp(msg);
    dst->on_message(&msg_wrp);
    
    return true;
}
//------------------------------------------------------------------------------

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

Далее, сообщение технически представляет собой тело сообщения - это тип, определяемый пользователем, который может быть произвольным - классом (или встроенным типом, но понятно, что идеологически правильно использовать класс или перечислимый тип - в общем, чтобы тип был уникальным), и класс-обёртку для тела сообщения - на каждый тип сообщения генерируется своя обёртка. Генерируется она на основе шаблона с аргументом в виде типа тела сообщения - шаблон msg_wrapper<>. Как видно из кода выше, этот шаблон генерирует классы, которые все являются производными от базового класса TBaseMsgWrapper, который является абстрактным базовым классом и определяет метод get_id(), который переопределяется в производных. Цель этого - чтобы в каждом производном классе эта функция возвращала уникальный идентификатор только своего класса, т.е. только соответствующего своему типу сообщений.

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

На приёме остаётся только проверить, что сообщение "свое", и если это так, то обработать его, в противном случае проигнорировать.

Использование. В приборе, для которого написана программа есть несколько кнопок управления (конкретно их 4 штуки). При нажатии на любую из них генерируется соответствующее событие, по котором формируется сообщение, посылаемое текущему активному объекту (указатель TObject *focus содержит адрес активного объекта).
Код
//------------------------------------------------------------------------------
     // где-то в заголовочном файле
    enum TKeyMessage
    {
        kmNONE,
        kmSEL,
        kmPOWER,
        kmPLUS,
        kmMINUS
    };

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

        gui::TKeyMessage key_code = gui::kmNONE;
        if( dev_key_events.sel.IsClick() )   // если кнопка "Select" нажата
        {
            key_code = gui::kmSEL;
            send_message<gui::TKeyMessage>(&key_code, focus);
        }
        if( power_key_event.IsClick() )
        {
            key_code = gui::kmPOWER;    // если кнопка "Питание" нажата
            send_message<gui::TKeyMessage>(&key_code, focus);
        }
        ...
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//
//  На приёме сообщения виджетами:
//
void TWidget::on_message(TBaseMsgWrapper *msg_wrp)
{
    gui::TKeyMessage *p = check_msg<gui::TKeyMessage>(msg_wrp);

    if(p)
    {
        switch(*p)
        {
        case gui::kmSEL:    handle(); break;
        case gui::kmPOWER:  back();   break;
        case gui::kmPLUS:   next();   break;
        case gui::kmMINUS:  prev();   break;
        default: print("Error");
        }
    }  
}
//------------------------------------------------------------------------------

Тут первым делом проверяется, соответствует ли тип сообщения ожидаемому. В частности, тут мы ждём сообщение типа TKeyMessage. Если реально сообщение будет другого типа, то функция check_msg() вернёт 0, и сообщение будет проигнорировано. Проверка сводится к банальному сравнению двух целых, что выполняется очень эффективно. Если тип сообщения соответствует ожидаемому, то будет возвращён указатель на тело сообщения, которое дальше может быть использовано по назначению. В частности, тут производится вызов функций в соответствии с информацией о нажатой кнопке прибора. Функции handle(), back(), next() и prev() являются виртуальными, изначально определены в TWidget и переопределяются в виджетах-потомках - это как раз тот случай, который был описан в предыдущем посте.

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

В общем, тут можно расширять и вверх, и вширь - т.е. создать столько типов сообщений, сколько нужно, и это всё без изменения остального (уже нередко стабильного) кода без опасности что-то поломать в нём. При этом не надо заботиться о правильности обработки - пользователь только создаёт тело сообщения, делает send_message() и check_message() в точке приёма. Всё остальное делает компилятор и сгенерированный код на рантайме.

* * *

Этот же приём был портирован на фреймворк Qt. Там особенность в том, что уже есть механизм передачи событий (QEvent) и при портировании было желание использовать его. Задумка у авторов Qt в части событий такова, что там события делятся на два типа - системные (всякие события от клавиатуры, мыши и прочего) и пользовательские. И предусмотрен идентификатор событий - целое. sm.gif Разделено там так: события от 0 до 1000 - это системные события, а от 1000 до 65535 - пользовательские. Реализация:
Код
#include <QApplication>
#include <QEvent>

//------------------------------------------------------------------------------
inline int generate_id() { static int id = QEvent::User; return ++id; }
//------------------------------------------------------------------------------
template<typename T> class msg_wrapper : public QEvent
{
public:
    msg_wrapper(T msg)
        : QEvent( static_cast<QEvent::Type>( get_class_id() ) )
        , body(msg)
    {
    }
    
    static  int get_class_id() { static const int id = generate_id(); return id; }
    
    T *get_msg() { return &body; }
    
private:
    T body;
};
//------------------------------------------------------------------------------
template<typename T> T *check_msg(QEvent *msg_wrp)
{
    if( msg_wrp->type() == msg_wrapper<T>::get_class_id() )
    {
        return (static_cast<msg_wrapper<T> *>(msg_wrp))->get_msg();
    }
    else
    {    
        return 0;
    }
}
//------------------------------------------------------------------------------
template<typename T> bool send_message(QObject *dst, T msg)
{
    msg_wrapper<T> msg_wrp(msg);
    return QApplication::sendEvent(dst, &msg_wrp);
}
//------------------------------------------------------------------------------

Использование. Тело сообщения - событие переименования элемента комбобокса:
Код
class TComboBoxRenameEvent
{
public:
    TComboBoxRenameEvent(QString NewValue): Value(NewValue){ }

    QString value() const { return Value; }

private:
    QString Value;
};


Сам класс комбобокса - в нём нужно переопределить функцию-обработчик события customEvent() (виртуальная).
Код
class TComboBox : public QComboBox
{
    Q_OBJECT

public:
    explicit TComboBox(QWidget *parent = 0) : QComboBox(parent) { }

    TComboBox & operator=(const TComboBox & );

protected:
    virtual void customEvent(QEvent *Message);
};


Генерация и отсылка сообщения (по кнопке Ok в диалоге переименования генерируется сигнал, к которому подконнекчен слот, представленный ниже):
Код
void TRenameDialog::on_pbOk_clicked()
{
    TComboBoxRenameEvent msg_body(ui->leName->text());
    send_message<TComboBoxRenameEvent>(Dst, msg_body);
}


И, наконец, приём и обработка сообщения:
Код
void TComboBox::customEvent(QEvent *Message)
{
    TComboBoxRenameEvent *msg = check_msg<TComboBoxRenameEvent>(Message);
    if( msg )
    {
         ...; // обработка сообщения
    }
}
//------------------------------------------------------------------------------

В общем-то, сама по себе идеология передачи событий в Qt очень похожа на описанную выше для embedded системы, она проста и логична, будучи основанной на передаче события в виде указателя на базовый класс. Но тут есть недостаток - приходится руками генерировать идентификатор типа, руками проверять на соответствие и делать явное преобразование типов (а явное преобразование типов - это, как правило, не гуд, и как утверждает тов. Страуструп: "...обычно указывает на ошибки проектирования", поэтому всегда желательно каждый такой случай рассматривать внимательно и при малейшей возможности прятать с глаз долой; в любом случае нехорошо, когда пользовательский код пестрит явными преобразования типов). Описанный приём просто все эти действия автоматизирует и предоставляет программисту более простой и безопасный интерфейс для использования.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jun 22 2011, 07:38
Сообщение #36


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата
Поясните? И причём тут множественное наследование? О нём вообще ни слова не было сказано.

С++ позволяет множественное наследование, вот и упомянул. Просто перечисление объективных недостатков языка.

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

Адресная арифметика - это также и чисто микроконтроллерная область. И хоть вы на чём пишите, залезать в неё придётся. А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.

Цитата
Да как обычно - чтобы избавиться от зависимости порядка создания объектов при раздельной компиляции файлов проекта. Затраты на него копеечные.

Ага, сначала создавать себе проблемы, используя С++, а потом мужественно их решать sm.gif

Цитата
А то, что голову надо включать, так это универсальное правило для любого ЯП.

На С++ голову уж слишком сильно нужно включать. Язык должен ограничивать программиста в его бурных устремлениях, а чрезмерная гибкость С++ позволяет выстрелить себе в ногу и успешно завалить проект. С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 22 2011, 08:13
Сообщение #37


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (andrewlekar @ Jun 22 2011, 13:57) *
В общем, это неправда, что С++ оправдан везде, где оправдан С.

Похоже, что назревает очередной спор (VS).


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 08:28
Сообщение #38


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(andrewlekar @ Jun 22 2011, 11:38) *
А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.


Набрался терпения и решил немного поработать писателем и корректором. Да, действительно адресная арифметика и динамическое размещение памяти при неопытности «да и опытности» тянет за собой источники потенциальных ошибок. Microsof, например, для решения этой проблемы и не только, разработал платформу .NET, под которую можно писать приложения на многих языках программирования, в частности применять C++ с расширением управляемости. (С++.Net). Код здесь, выполняется под управлением обще языковой среды выполнения CLR (Common Language Runtime), называется «управляемым кодом». Программы состоят из кода и данных, и обще языковая среда выполнения CLR обеспечивает поддержку и управляемым данным, и управляемому коду. Управляемые данные размещаются в управляемой динамически распределяемой области памяти (куче), которая имеет весьма ценную особенность — автоматическую сборку мусора (garbage collection). Если при создании программ на обычном C++ программист должен сам создавать средства управления динамически распределяемой областью памяти, то обще языковая среда выполнения CLR реализует этот процесс, отслеживая ссылки на объекты и автоматически освобождая ресурсы, занятые объектами, которые стали недоступны программе. Фактически, управляемые и неуправляемые (к которому мы все так привыкли) код и данные на C++ могут быть определены в одном и том же исходном файле, и в некоторой степени эти два мира могут взаимодействовать. Хотя использование управляемого кода и данных имеет много преимуществ (пример выход за пределы массива, на этапе run-time сразу выбросит исключение) оно может привести к снижению производительности и потере гибкости. Поэтому во многих случаях неуправляемый C++, при опытности и знаниях, оказывается лучшим выбором для создания программ.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 22 2011, 08:32
Сообщение #39


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



По сравнению с уважаемым dxp, я вообще не программист crying.gif Но, тем не менее, позволю изложить и свою точку зрения.

QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
Адресная арифметика - это также и чисто микроконтроллерная область

А к чему это уточнение? С адресами на любой платформе работать приходится.
QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.

Не обязательно на Си++ размещать объекты динамически. Я не размещаю. А если размещаете, то нужно делать это корректно.
QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
На С++ голову уж слишком сильно нужно включать.

Ну так это инструмент профессиональный rolleyes.gif
QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
Язык должен ограничивать программиста в его бурных устремлениях, а чрезмерная гибкость С++ позволяет выстрелить себе в ногу и успешно завалить проект. С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.

А почему Вы считаете, что разработчики компилятора знают лучше, что мне можно, а что - нельзя. В этих случая Pascal нужно выбирать. Он ограничивал.


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Jun 22 2011, 08:35
Сообщение #40


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(Hellper @ Jun 19 2011, 03:15) *
Такие примеры, чтобы показывали удобство и силу использование ООП, и тянуло сразу садится, вникать и кодить.


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

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


Код
base_service.h
///@class ClBaseService
///@brief Base class for services.
/// All classes, which inherited from ClBaseService will receive message from SystemService
class ClBaseService: public TClMulticastHandler<ClSystemMessage>
{
* * *
    ///@brief Called when receive message from SystemService
    ///@param clSend_ - message from SystemService
    int ProcessMulticast(ClSystemMessage& clSend_);
* * *
};



Код
system_service.h

///@class ClSystemService
///@brief System service of environment.
class ClSystemService: public TClSingleton<ClSystemService>
{
  friend class TClSingleton<ClSystemService>;
* * *
  public:
    ///@brief Send INIT signal to all services
    ///@return Count of detected errors
    int InitServices()
    {
      DebugOut("[SystemService] Init services:\n");

      // Send INIT message
      ClSystemMessage clInitMessage_(ClSystemMessage::E_INIT);
      int i32ServiceCount_ = TClMulticastEventMech<ClSystemMessage>::EmitEvent(clInitMessage_);
      
      DebugOut("**[Init %i services, %i errors]\n\n", i32ServiceCount_, clInitMessage_.u32ErrorCounter_m);
      return i32ServiceCount_;
    }
* * *
};


Прошу прощения за "портянку", почему-то не удается ни архив, ни заголовочник прикрепить
Код
#ifndef __MULTICAST_EVENT_HEADER_H__
#define __MULTICAST_EVENT_HEADER_H__

#include "sync_obj.h"
#include "singleton.h"

#include <stdint.h>

namespace ENV
{

template <class SEND_MSG>
class TClMulticastEventMech;

///@class TClMulticastHandler
///@brief Parent class for objects, which want use multicast messages
template <class SEND_MSG>
class TClMulticastHandler
{
  friend class TClMulticastEventMech<SEND_MSG>;
  protected:
    /// Protected constructor
    TClMulticastHandler();
    /// Protected virtual destructor
    virtual ~TClMulticastHandler();
    
    ///@brief Abstract method for message receiption.
    /// Will be called when someone send message with appropriate types
    /// @param clSend_ - parameter type SEND_MSG. Read only
    /// @return can't defined. Value may be used in users purposes
    virtual int ProcessMulticast(SEND_MSG& clSend_)= 0;
};


///@class TClMulticastEventMech
///@brief Pool of requestors for one-type messages
template <class SEND_MSG>
class TClMulticastEventMech:public TClSingleton<TClMulticastEventMech<SEND_MSG> >
{
  typedef       TClMulticastHandler<SEND_MSG> THandler;
  friend class  TClSingleton<TClMulticastEventMech<SEND_MSG> >;
  friend class  TClMulticastHandler<SEND_MSG>;

  public:
    ///@brief Max count of handlers for one-type message
    static const uint32_t MAX_HANDLERS = 32;
    
    ///@brief Send message to all registered requestors
    ///@param pclSend_ - pointer to const message
    static int EmitEvent(SEND_MSG& clSend_)
    {
      return TClMulticastEventMech<SEND_MSG>::Instance()->EmitEvent_nonstatic(clSend_);
    }                      
    
    ///@brief Send message to all registered requestors, except sender
    ///@param pclSend_ - pointer to const message
    ///@param pclSender_ - pointer to sender
    static int EmitEvent(SEND_MSG& clSend_, THandler* pclSender_)
    {
      return TClMulticastEventMech<SEND_MSG>::Instance()->EmitEvent_nonstatic(clSend_, pclSender_);
    }
    
    ///@brief Send message to all registered requestors, except sender
    ///@param pclSend_ - pointer to const message
    ///@param pclSender_ - pointer to sender
    static int EmitEvent(SEND_MSG& clSend_, void* pclSender_)
    {
      return TClMulticastEventMech<SEND_MSG>::Instance()->EmitEvent_nonstatic(clSend_);
    }

      
  private:
    ///Pool of requestors
    THandler* apclHandlers_m[MAX_HANDLERS];

    ///Count of registered requestors
    uint32_t      u32CountHandlers_m;
  
    ///Private constructor. Create object can only TClSingleton
    TClMulticastEventMech():u32CountHandlers_m(0){}
    
    ///Register reqiestor
    ///@param pclHandler_ - pointer to requestor object
    int Register(THandler* pclHandler_);

    ///Unregister requestor
    ///@param pclHandler_ - pointer to requestor object
    int UnRegister(THandler* pclHandler_);

    ///Hide copy constructor  
    TClMulticastEventMech(const TClMulticastEventMech&){}              
    
    ///@brief Send message to all registered requestors
    ///@param pclSend_ - pointer to const message
    ///@param pclRecv_ - pointer to message (usually use as reply)
    inline int EmitEvent_nonstatic(SEND_MSG& clSend_)
    {
      //Process all requestors
      for (uint32_t i=0; i<u32CountHandlers_m; ++i)
        apclHandlers_m[i]->ProcessMulticast(clSend_);
      return u32CountHandlers_m;
    }                  
    
    ///@brief Send message to all registered requestors, except sender
    ///@param pclSend_ - pointer to const message
    ///@param pclSender_ - pointer to sender
    inline int EmitEvent_nonstatic(SEND_MSG& clSend_, THandler* pclSender_)
    {
      //Process all requestors
      for (uint32_t i=0; i<u32CountHandlers_m; ++i)
        if (apclHandlers_m[i] != pclSender_)
          apclHandlers_m[i]->ProcessMulticast(clSend_);
          
      return u32CountHandlers_m;
    }
};


////////////////////////////////////////////////////////////////////////////////    
template <class SEND_MSG>    
  int TClMulticastEventMech<SEND_MSG>::Register(TClMulticastEventMech::THandler* pclHandler_)
  {
    TClCriticalSection<true> clCS_;

    //Check overfull requestors list
    if (u32CountHandlers_m == MAX_HANDLERS)
      Halt("TClMulticastEventMech::Register(): Count of handlers are big");

    apclHandlers_m[u32CountHandlers_m] = pclHandler_;
    return ++u32CountHandlers_m;
  }

////////////////////////////////////////////////////////////////////////////////
template <class SEND_MSG>
  int TClMulticastEventMech<SEND_MSG>::UnRegister(TClMulticastEventMech::THandler* pclHandler_)
  {
    Halt("TClMulticastEventMech::UnRegister: Unsupported!\n");
    return 0;
  }      


////////////////////////////////////////////////////////////////////////////////
template <class SEND_MSG>
  TClMulticastHandler<SEND_MSG>::TClMulticastHandler()
  {
    TClMulticastEventMech<SEND_MSG>::Instance()->Register(this);
  }
  

////////////////////////////////////////////////////////////////////////////////
template <class SEND_MSG>
  TClMulticastHandler<SEND_MSG>::~TClMulticastHandler()
  {
    TClMulticastEventMech<SEND_MSG>::Instance()->UnRegister(this);
  }


} //namespace ENV

#endif //__MULTICAST_EVENT_HEADER_H__
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 08:37
Сообщение #41


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(andrewlekar @ Jun 22 2011, 11:38) *
С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.


С ОЗУ до 4kBytes - да, но новые МК имеют уже под сотню kBytes, как не вертись, тут увы, Вы не правы!


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jun 22 2011, 08:44
Сообщение #42


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(andrewlekar @ Jun 22 2011, 10:38) *
Адресная арифметика - это также и чисто микроконтроллерная область. И хоть вы на чём пишите, залезать в неё придётся. А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.


Ага, сначала создавать себе проблемы, используя С++, а потом мужественно их решать sm.gif


На С++ голову уж слишком сильно нужно включать. Язык должен ограничивать программиста в его бурных устремлениях, а чрезмерная гибкость С++ позволяет выстрелить себе в ногу и успешно завалить проект. С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.



Все ваши высказывания от недостаточного знания и опыта работы с С++.

1. По поводу статической аллокации в С. И что тут такого сильно удобного? А если памяти не хватает все сразу и навсегда разместить? Не сталкивались с таким?

2. В С++ ошибки при работе с динамической памятью как раз резко сократились за счет того, что многие вещи делает компилятор автоматически (конструктор/деструктор).

3. Сам потратил много сил на перевод фирменных изделий с концепции С со статическим размещением переменных на С++ со всеми его вкусностями. Да, требуется время для продумывания концепции, реализации и отладки своих библиотек классов. Зато потом наступает полная лепота при необходимости расширения функционала устройства. Быстро и просто.

4. Насчет ненадежности работы устройств при их реализации на С++. Совершенно ничем необосновано. У нас устройства как раньше работали месяцами без перезагрузки, так и сейчас работают.
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jun 22 2011, 09:00
Сообщение #43


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата(haker_fox @ Jun 22 2011, 14:32) *
А почему Вы считаете, что разработчики компилятора знают лучше, что мне можно, а что - нельзя. В этих случая Pascal нужно выбирать. Он ограничивал.

Потому что разработчики компиляторов умные, а программист только-только Hello World освоил. sm.gif Pascal - это хорошо, но лучше Java или .NET. Вообще во всём мире С++ верно помирает, а вы наоборот в контроллеры его суете.

Цитата(sergeeff @ Jun 22 2011, 14:44) *
Все ваши высказывания от недостаточного знания и опыта работы с С++.

На С++ я успел поработать и мне не понравилось. И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде. Да, при хорошем опыте программист научается ходить по этим граблям, но новый программист в проекте будет разбираться очень долго. sm.gif

Цитата(sergeeff @ Jun 22 2011, 14:44) *
1. По поводу статической аллокации в С. И что тут такого сильно удобного? А если памяти не хватает все сразу и навсегда разместить? Не сталкивались с таким?

2. В С++ ошибки при работе с динамической памятью как раз резко сократились за счет того, что многие вещи делает компилятор автоматически (конструктор/деструктор).

Один говорит, что статическая аллокация хороша при малом объеме ОЗУ. Другой наоборот. Да, бывает, что без динамической аллокации не обойтись - тогда приходится идти на компромисс.
Что-то я не слыхал, чтобы в С++ где-то резко сократились ошибки памяти. Наоборот, прибавилось ошибок. Утечки памяти - фирменная фича неуправляемого С++. В бусте напихали целую кучу умных указателей для борьбы с утечками и всё равно регулярно где-то подтекает на больших проектах.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 22 2011, 09:32
Сообщение #44


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(andrewlekar @ Jun 22 2011, 13:00) *
И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде.

А я так думаю наоборот - прячут с глаз долой всё лишнее и второстепенное, мешающее целостному восприятию кода.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
shreck
сообщение Jun 22 2011, 10:34
Сообщение #45


Местный
***

Группа: Свой
Сообщений: 327
Регистрация: 24-06-06
Из: Томск
Пользователь №: 18 328



Цитата(andrewlekar @ Jun 22 2011, 16:00) *
... но лучше Java или .NET...

... И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде. Да, при хорошем опыте программист научается ходить по этим граблям, но новый программист в проекте будет разбираться очень долго. sm.gif

Так и шаблоны и перегрузки и ОО есть и в вашем любимом .NET. Получается, что в С++ эти фичи разводят грязь, а в .NET все чистенько? Это при том, что синтаксис C# очень близок к С++.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 22 2011, 11:14
Сообщение #46


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



История моей жизни. Когда-то очень давно, когда компьютеры были большие, микроконтроллеры были 8080, а персональный компьютер был IBM PC/XT с тактовой частотой аж 4.77 MHz.... Но тем не менее фирма Borland выпустила для персоналки первый компилятор C++ V1.0. Я, имея приличный опыт писания на FORTRAN и немного на ASM (хотя наверное приличный, потому-что BOIS для XT у которой сдохла оная пззушка я таки написал), решил воспользоваться плюсами дабы написать программатор РФ-ок. Естественно с окошками, редакторами и прочим. Окошки, конечно, не GUI, а текстовые. Рядом был программист имеющий достаточно большой для тех времен опыт писания на C, и очень отговаривавший меня от C++ - типа громоздко, криво, тормозаааа..... Но я был упорным sm.gif. Сидел, грыз книгу, думал, проникался.... Кончилось все спором, кто напишет оконную библиотеку более быструю ( тогда на XT скорость прорисовки можно было вообще наблюдать невооруженным глазом sad.gif ) компактнную и за ограниченное время.
Спор при все своей опытности коллега проиграл - уж больно все окошки на плюсы хорошо легли sm.gif. Потом правда отыгрался - полез в наглую ASM встави делать, подчищать...
Я правда в тоже туда-же. В общем библиотечка удалась и использовал я ее долго....Как и C++. Потом пришло осознание того, что Борлондячий компилятор дерьмо редкое, пришлось переходить на другие, пришлось использовать С, поскольку времена были стародавние и плюсовых компиляторов было немного sad.gif. Как-то получалось так, что я начал писать в даже на С++ в посконном С стиле, дабы портировать можно было-бы без больших переделок. В общем, я сейчас на плюсах пишу редко, но я не представляю себе, как-бы я писал на C не пройдя школу С++. Там есть масса вещей и подходов которые НЕОБХОДИМО осознать, понять и использовать вне зависимости от языка. Еще скажу, что компиляторы (особо С++) в те времена были реально неумные и ручками на С их при ДОСТАТОЧНОМ ОПЫТЕ можно было таки уделать. Все не стояло на месте - на С++ компиляторы теперь грех жаловаться. Коллеги! Учите и проникайтесь идеями С++, даже если потом будете на BASIC писать.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
SergeyDDD
сообщение Jun 22 2011, 11:22
Сообщение #47


Местный
***

Группа: Свой
Сообщений: 231
Регистрация: 7-12-06
Из: Киев
Пользователь №: 23 248



Цитата(andrewlekar @ Jun 22 2011, 12:00) *
Что-то я не слыхал, чтобы в С++ где-то резко сократились ошибки памяти. Наоборот, прибавилось ошибок. Утечки памяти - фирменная фича неуправляемого С++. В бусте напихали целую кучу умных указателей для борьбы с утечками и всё равно регулярно где-то подтекает на больших проектах.


Вы реально пишите глупости...
Очевидно что для Вас вопрос выбора между С и С++ это вопрос религии и только
Поэтому я бы Вам советовал быть более объктивным уж если Вы пытаетесь давать определенные оценки

А если у Вас был неудачный опыт с С++, ну тогда думаю сами знаете что "хорошему" танцору мешает

А "ошибки памяти", "Утечки памяти" и прочее прочее это "фирменная фича" неаккуратных и безграмотных "специалистов" а не "неуправляемого С++"
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 22 2011, 11:30
Сообщение #48


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (andrewlekar @ Jun 22 2011, 18:00) *
Потому что разработчики компиляторов умные, а программист только-только Hello World освоил. sm.gif

if(разработчики_компилятор != программисты)
{
мир_в_хаосе_и_я_ничего_не_понимаю_в_нем();
panic_kernel(&мой_мозг);
}

Дайте маленькому ребётенку острый нож, и получите тот же эффект: ребенок будет считать нож злом и говорить всем, что ножом нельзя пользоваться rolleyes.gif
QUOTE (andrewlekar @ Jun 22 2011, 18:00) *
Вообще во всём мире С++ верно помирает, а вы наоборот в контроллеры его суете.

Да? А мужики-то не знают rolleyes.gif Может будем в МК вставлять .NET и Java сразу?
QUOTE (andrewlekar @ Jun 22 2011, 18:00) *
На С++ я успел поработать и мне не понравилось. И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде. Да, при хорошем опыте программист научается ходить по этим граблям, но новый программист в проекте будет разбираться очень долго. sm.gif

Это все субъективно. Есть люди и с противоположным мнением. Кстати, не каждый новый программист код на чистом Си разберет.


Я бы скромно предложил закрыть тему, как воинствующую)))

QUOTE (zltigo @ Jun 22 2011, 20:14) *
хотя наверное приличный, потому-что BOIS для XT у которой сдохла оная пззушка я таки написал

Мое Вам уважение! Я дальше самописного бутлоадера (на нулевой дорожки дискеты) и попытки написать примитивную миниОС в защищенном режиме IA32 не ушел. Но это было в далеком 2004 году, сейчас я немного взрослее стал))) Хотя, надо признаться, опыт был неплохой получен. Также делал окна в текстовом режиме, кнопочки и т.д. и т.п. Все на ассемблере...


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 11:31
Сообщение #49


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Кстати, прорабатывается новая версия стандарта С++ - это С++ 0x, главной задачей которого является развитие языка С++. Вот тут впринципе не плохо описано, можно пичитать: тыц


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 22 2011, 11:45
Сообщение #50


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Danis @ Jun 22 2011, 15:31) *
Кстати, прорабатывается новая версия стандарта С++ - это С++ 0x, главной задачей которого является развитие языка С++. Вот тут впринципе не плохо описано, можно пичитать: тыц

Ну, наконец-то!
Цитата
В стандартном C++ для перебора элементов коллекции требуется масса кода. В некоторых языках, например, в C#, есть средства, предоставляющие «foreach»-инструкцию, которая автоматически перебирает элементы коллекции от начала до конца. C++0x вводит подобное средство. Инструкция for позволит проще осуществлять перебор коллекции элементов:
Код
int my_array[5] = {1, 2, 3, 4, 5};
for(int &x : my_array)
{
  x *= 2;
}

Эта форма for, называемая в английском языке «range-based for», посетит каждый элемент коллекции. Это будет применимо к C-массивам, спискам инициализаторов и любым другим типам, для которых определены функции begin() и end(), возвращающие итераторы. Все контейнеры стандартной библиотеки, имеющие пару begin/end, будут работать с for-инструкцией по коллекции.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 22 2011, 12:33
Сообщение #51


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (haker_fox @ Jun 22 2011, 14:30) *
Я дальше ....

Уж больно у меня стимул был велик - в 80-е годы заполучить ПЕРСОНАЛЬНЫЙ!! КОМПЬЮТЕР! дома!!! По этой причине моей первой программой на ASM 8088 стал BIOS sm.gif. Ох, помнится, и попотел я.... А еще он мог, как с родными работать с 800K дискетами sm.gif sm.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 21 2011, 22:05
Сообщение #52


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Пописал немного кода на С++ использованием динамического полиморфизма и шаблонов...
компиллер юзал gcc-4.6.1. всякую динамическую дрянь, rtti ессно поотключал.
Про конструкторы и деструкторы правда пришлось забыть, тк память под обьект обычно выделяется статически(читай, во время ресета контроллера),
а инициализировать его можно аж после загрузки какой-то части ОС, при чем для разных классов это может быть по разному (на пример гуи должен стартовать после драйверов итп).
Хотя завести init() вместо конструктора для каждого класса и вызвать в нужном месте для нужного обьекта не составляет особого труда.

Ради интереса взял кусок своей старой чисто-сишной гуи-либы под 128х64 монохромный дисплей и переписал на С++.
В сишной версии рулили всем указатели на таблицы функций(таких как draw,keypressed,...)
После переноса этого на плюсы, все было заменено на классы с виртуальными ф-ями и рулить стали указатели на обьекты.
Хохма - асм-код остался Идентичен по размеру и инструкциям, только адреса поменялись! А исходник на плюсах стал меньше и гораздо красивее.
Оказывается, я уже давно юзаю оо, но все руцями sm.gif

Далее перевел на плюсы с использованием шаблонов thread-safe queue, сишная версия которого пестрела макросами для реализации поддержки разных типов данных(время на написание этих макросов ушо больше, чем бы я писал отдельные функции для каждого типа sm.gif)
Тут сгенерированный код остался Полностью Идентичен сишной версии sm.gif

В итоге исходный код гораздо проще для понимания, и главное - его просто меньше. Синтаксис обычный сишный. Потери производительности - нулевые.

Еще
От множественного наследования отказался сразу. Имхо,для 256кб флеша оно не надо, да и во многих оо-языках его нету
Обработку исключений не пробовал. по идее, если ее правильно реализовать в компиляторе - производительность должна повысится, в свравнении с техникой возврата кода ошибки, неговоря уже о красоте кода( куча дефайнов с кодами ошибок, куча if,goto, путаница где вызвать printf, где нет итп). Хотя оно не избавляет от проблем выделения/освобождения ресурсов: выделили 10 ресурсов, 11й не вышло - надо освобождать все обратно, а обработчик знать не может что там выделено и сколько, особенно,если там куча вложенных функций, которые тоже что-то выделяли. в итоге городить if/goto всеравно прийдется...
Перегрузка операторов и потоков пока вроде не нужна. не нашел места применения. думалось заюзать перегрузку +-=/*% для работы с большими числами(скажем в 2048бит, нужно для таких алгоритмов, как RSA,DSA,...), но очередность там не однозначная получается,многое зависит от компилятора(особенно он любит пихат оператор = там,где не надо), в итоге пожирается память, вызывается довольно тяжелые функции лишний раз, а красота кода не сильно улучшается.
на пример а=(b*c)%m
у меня:
mul(t,b,c);
mod(a,t,m);
а иногда, если размер a больше чем размер b+c
mul(a,b,c);
mod(a,a,m);

у gcc
mul(t,b,c);
mod(t1,t,m);
equ(a,t1,m);
а иногда еще хуже, когда несколько вложенных скобок...

по поводу C++11, имхо для embedded ничего полезного. кроме как инициализация отдельных полей структур по имени(уже давно есть в C, в C++ никак не перекочует). Еще в c++ нету VLA (variable length array) - создние в стеке массива неконстантной длины.в c99 это есть и прекрасно работает(при аккуратном использовании) - экономит память.
Go to the top of the page
 
+Quote Post
777777
сообщение Sep 22 2011, 04:49
Сообщение #53


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(dxp @ Jun 20 2011, 11:32) *
  1. Почему вы ставите знак равенства между С++ и ООП?

Потому что С++ - это язык ООП. Всё остальное, что в нем есть - это (ненужные) навороты, главная его особенность - объектная ориентированность.

Цитата(andrewlekar @ Jun 22 2011, 13:00) *
Что-то я не слыхал, чтобы в С++ где-то резко сократились ошибки памяти. Наоборот, прибавилось ошибок. Утечки памяти - фирменная фича неуправляемого С++.

О как! Сильно сказано. Только вот как раз ООП и придумано для того, чтобы можно было не сократить, а полностью ликвидировать утечки памяти - просто нужно тщательно продумать структуру программы и распределение объектов. И выделять память в конструкторе объекта, а удалять в деструкторе. Тогда их не будте никогда. Разве что у тех программистов, которые так и не поняли смысл объектно-ориентированного программирования.

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
С++ позволяет множественное наследование, вот и упомянул. Просто перечисление объективных недостатков языка.

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

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
Адресная арифметика - это также и чисто микроконтроллерная область. И хоть вы на чём пишите, залезать в неё придётся.

Зачем? Вот убей не пойму, почему когда пишут прикладную программу для обычного компьютера, она не требуется, а в микроконтроллерах непременно нужна?

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.

Динамическое размещение объектов встречается везде, но в C нет средств для аккуратной работы с ними, а в C++ есть.

Цитата(andrewlekar @ Jun 22 2011, 11:38) *
На С++ голову уж слишком сильно нужно включать.

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

Сообщение отредактировал 777777 - Sep 22 2011, 04:49
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 22 2011, 07:25
Сообщение #54


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(brag @ Sep 22 2011, 05:05) *
Про конструкторы и деструкторы правда пришлось забыть, тк память под обьект обычно выделяется статически(читай, во время ресета контроллера),
а инициализировать его можно аж после загрузки какой-то части ОС, при чем для разных классов это может быть по разному (на пример гуи должен стартовать после драйверов итп).
Хотя завести init() вместо конструктора для каждого класса и вызвать в нужном месте для нужного обьекта не составляет особого труда.

Чем же так конструкторы не угодили? Это просто удобно и безопасно - автоматическая инициализация при создании объектов. А с отдельным init'ом обычное дело забыть сунуть туда инициализатор (люди постоянно ошибаются sm.gif ).

Цитата(brag @ Sep 22 2011, 05:05) *
От множественного наследования отказался сразу. Имхо,для 256кб флеша оно не надо,

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

Цитата(brag @ Sep 22 2011, 05:05) *
Обработку исключений не пробовал. по идее, если ее правильно реализовать в компиляторе - производительность должна повысится, в свравнении с техникой возврата кода ошибки, неговоря уже о красоте кода( куча дефайнов с кодами ошибок, куча if,goto, путаница где вызвать printf, где нет итп).

Не, обработка исключений точно не катит в embedded - это самый тяжёлый механизм С++. Там при выбросе исключения происходит так называемая "раскрутка стека", это длительный процесс со слабопредсказуемыми времянками и значительным потреблением ресурсов - процессорного времени.

Цитата(brag @ Sep 22 2011, 05:05) *
по поводу C++11, имхо для embedded ничего полезного.

Полезная фишка там есть - rvalue reference (обозначается оператором &&). Позволяет избежать ненужного копирования в ряде случаев.

Цитата(777777 @ Sep 22 2011, 11:49) *
Потому что С++ - это язык ООП. Всё остальное, что в нем есть - это (ненужные) навороты, главная его особенность - объектная ориентированность.

Правда? Т.е. сами по себе классы нафиг не нужны? И перегрузка имён функций/операторов не нужна? И возможность объявлять объекты в любом месте программы не нужна? И наследование (без виртуальных функций) не нужно? И шаблоны не нужны?

Да будет вам известно, что исходно С++ появился именно как объектный язык, и ОО составляющая была в него добавлена значительно (годы) позже.

С++ никогда не был чистым ОО языком - ООП в нём - это лишь один (и не очень обширный) из его аспектов.

Либо (если не согласны в вышеперечисленным) вы не вполне понимаете, что такое ООП.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Sep 22 2011, 09:51
Сообщение #55


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Код
Про конструкторы и деструкторы правда пришлось забыть, тк память под обьект обычно выделяется статически(читай, во время ресета контроллера)


При embedded программировании надо, для начала, понять, как устроен конкретный компилятор и его startup файл, где и в каком порядке что должно инициализироваться. Тогда вы будете управлять процессом проектирования, а не идти на поводу "левых" demo проектов.
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 12:11
Сообщение #56


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Чем же так конструкторы не угодили? Это просто удобно и безопасно - автоматическая инициализация при создании объектов. А с отдельным init'ом обычное дело забыть сунуть туда инициализатор (люди постоянно ошибаются ).

Да, это удобно и на PC я их использую во всю. а вот конкретно на моей платформе с ними проблеммы...
Кога обьект размещен в статической памяти(у меня это только bss забиваемый при старте нулями), gcc создает:
1. константную таблицу init_array с указателями на функции(те самые конструкторы/инициализаторы указателей на vtables). Ессно, если в классе есть виртуальные функции, то GCC по любом создаст конструктор либо дополнит существующий кодом инициализации указателя на vtable
2. саму констнтую vtable
пример
Код
class A{
public:
    virtual int a()=0;
};

class B :public A{
public:
    B(){z=0x12345;};
    int a(){return z++;};
private:
    int z;
};

B bcc;

Код
Disassembly of section .text:
00008004 <_GLOBAL__sub_I_bcc>:
    8004:    f240 034c     movw    r3, #76; 0x4c
    8008:    f242 3245     movw    r2, #9029; 0x2345
    800c:    4903          ldr    r1, [pc, #12]; (801c <_GLOBAL__sub_I_bcc+0x18>)
    800e:    f2c0 0301     movt    r3, #1
    8012:    f2c0 0201     movt    r2, #1
    8016:    e883 0006     stmia.w    r3, {r1, r2}
    801a:    4770          bx    lr
    801c:    00008038     andeq    r8, r0, r8, lsr r0
00008020 <_ZN1B1aEv>:
    8020:    6843          ldr    r3, [r0, #4]
    8022:    1c5a          adds    r2, r3, #1
    8024:    6042          str    r2, [r0, #4]
    8026:    4618          mov    r0, r3
    8028:    4770          bx    lr
    802a:    bf00          nop
Disassembly of section .rodata:
00008030 <_ZTV1B>:
    8038:    00008021     andeq    r8, r0, r1, lsr #32
Disassembly of section .init_array:
00010048 <__data_start-0x4>:
   10048:    00008005     andeq    r8, r0, r5

В итоге, функции по указателям в .init_array должны буть когда-то вызваны до использования обьекта.
НО. Некоторые обьекты нужно проинициализировать сразу после ресета(до старта ОС).
Некоторые после старта ОС но до старта конкретных драйверов периферии. почему - потому что в их конструкторах есть вызовы функций ОС, если их вызвать до старта ОС - будет креш.
А некоторые после старта всех драйверов и до выполнения первого юзерского треда(приложения). Аналогично - там могут быть обращения к дровам, выделение системных ресурсов(создание тредов, мютексов итд).
В итоге как мне знать когда вызвать ту или иную функцию(конструктор) из init_array ?
Потому я пошел по простому пути - отказался от конструкторов; обрабатываю init_array(туда компиллер кидает код инициализации указателей на vtable) еще до старта системы, что есть безопасно, тк в конструкторах нету системозависимого кода; А уже инициализацию обьектов провожу явно в нужном месте в нужное время посредством вызова init();
Думаю понятно изложил wink.gif

Цитата
Необходимость в множественном наследовании зависит не от объёмов программы, а от её концепции и задач. Например, когда надо объединить функционал двух объектов, удобно отнаследоваться от них обоих. Кода это не добавляет.

Ну мож иногда и надо, я пока применению ему не нашел. а про 256кб упомянул с намеком на относительную простоту програм с данным обьемом sm.gif

Цитата
Не, обработка исключений точно не катит в embedded - это самый тяжёлый механизм С++. Там при выбросе исключения происходит так называемая "раскрутка стека", это длительный процесс со слабопредсказуемыми времянками и значительным потреблением ресурсов - процессорного времени.

При выбросе исключения явно(путем возврата кода ошибки) тоже происходит раскрутка стека - мы же вернемся в самую первую функцию по цепочке из кодов ошибок: типа ошибка вылезла в недрах uartRead, выходим uartRead->SysCall->GsmModemMuxRead->GsmModemCommand->GprsWrapper->TermRead->main...
Хотя с вами соглашусь, "обработка исключений точно не катит в embedded"

Цитата
Полезная фишка там есть - rvalue reference (обозначается оператором &&). Позволяет избежать ненужного копирования в ряде случаев.

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

Цитата
При embedded программировании надо, для начала, понять, как устроен конкретный компилятор и его startup файл

Привязыватся к компилятору - плохая идея. Мой код дожен компилится любым нормальным компилятором и работать.
Компилятор для меня - это именно КОМПИЛЯТОР, тобышь генератор кода, а не набор библиотек и прочей несовместимой хрени.
startup у меня свой равно как и ОС. Там и MPU задействован, и куча всяких вкусностей типа lock-free фишек итп, все это не совместимо ни с стандартной библиотекой ни с стартапами(которые тоже являются частью стдлиб), но зато очень удобно в ислопользовании.

Цитата
где и в каком порядке что должно инициализироваться

как я уже писал - компилятор никак не может знать что за чем должно инициализироватся, в сучаи одновременного создания обьектов,тобышь в статической памяыти, ни я не могу быть 100% уверен,что компиллер вдруг запустит конструктор не там, где нужно.
Если обьект создается в стеке - тогда да, там можно запросто юзать конструкторы/деструкторы,да и выделение глобальных системных ресурсов для обьекта в стеке конкретного треда/прерывания не целесобразно.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Sep 22 2011, 12:32
Сообщение #57


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Насколько я понимаю, вот тут конструктор object будет вызван в момент первого вызова GetObject(), а не ещё до main() в порядке, определяемом линковкой файлов.
Код
Object& GetObject()
{
    static Object object;
    return object;
}

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


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 12:47
Сообщение #58


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Насколько я понимаю, вот тут конструктор object будет вызван в момент первого вызова GetObject(), а не ещё до main() в порядке, определяемом линковкой файлов.

Зависит от компилятора... счас проверим на GCC
Цитата
Только радости от этого по сравнению с object.init() мало -- добавляется кусочек кода в каждом использовании, функции object при вызове GetObject().send() не проинлайнятся, ...

по моему init() гораздо красивее этой конструкции...возможности языка нужно применять не ради самих возможностей, а для дела(пользы). благо, Страуструп заложил в язык 2 важные вещи:
1. Он должен быть пригоден для системного программирования (те в окружении неизвестному компилятору,не зависящему одно от другого)
2. Мы не должны платить за то, чего не используем. не конструктора - не паримся с его поддержкой, нет new/delete - не паримся с поддержкой динамики итд...
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 22 2011, 13:03
Сообщение #59


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(brag @ Sep 22 2011, 19:11) *
НО. Некоторые обьекты нужно проинициализировать сразу после ресета(до старта ОС).
Некоторые после старта ОС но до старта конкретных драйверов периферии. почему - потому что в их конструкторах есть вызовы функций ОС, если их вызвать до старта ОС - будет креш.
А некоторые после старта всех драйверов и до выполнения первого юзерского треда(приложения). Аналогично - там могут быть обращения к дровам, выделение системных ресурсов(создание тредов, мютексов итд).
В итоге как мне знать когда вызвать ту или иную функцию(конструктор) из init_array ?

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

Цитата(brag @ Sep 22 2011, 19:11) *
Ну мож иногда и надо, я пока применению ему не нашел. а про 256кб упомянул с намеком на относительную простоту програм с данным обьемом sm.gif

256 кБ - весьма приличный объём, если писать код своими руками (а не забить его библиотечными функциями). А по меркам embedded так даже и нифига себе. sm.gif

Цитата(brag @ Sep 22 2011, 19:11) *
При выбросе исключения явно(путем возврата кода ошибки) тоже происходит раскрутка стека - мы же вернемся в самую первую функцию по цепочке из кодов ошибок: типа ошибка вылезла в недрах uartRead, выходим uartRead->SysCall->GsmModemMuxRead->GsmModemCommand->GprsWrapper->TermRead->main...

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

Цитата(brag @ Sep 22 2011, 19:11) *
Я привык руцями управлять перегонкой данных, ссылки использую в очень редких случаях, в основном только указатели. при паре сотен байт стека, имхо, это дело надо контролировать самому...

Rvalue reference - это совсем не те ссылки, которые в нынешнем С++. Это совсем другая штука. sm.gif Обычные ссылки, кстати, тоже, имхо, зря обделяете вниманием - они в ряде случаев дают более простую семантику и более безопасный код.



Цитата(brag @ Sep 22 2011, 19:47) *
по моему init() гораздо красивее этой конструкции...

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 13:13
Сообщение #60


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Object& GetObject()
{
static Object object;
return object;
}

Хе, еще хуже. Компиллер создает в bss переменную-флаг был ли создан обьект или нет.
Далее он проверяет этот флаг. если он не установлен - вызывает функцию __cxa_guard_acquire, которая должна заблокировать этот обьект(типа открыть мютекс) и далее запускает конструктор. потом вызывает __cxa_guard_release и возвращает указатель/ссылку на обьект. sm.gif
Ессно тело этих функций лежит на нас. И ессно это гемор, проще вызвать init(...) в нужном месте і все
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 22 2011, 13:19
Сообщение #61


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(brag @ Sep 22 2011, 20:13) *
Хе, еще хуже. Компиллер создает в bss переменную-флаг был ли создан обьект или нет.
Далее он проверяет этот флаг. если он не установлен - вызывает функцию __cxa_guard_acquire, которая должна заблокировать этот обьект(типа открыть мютекс) и далее запускает конструктор. потом вызывает __cxa_guard_release и возвращает указатель/ссылку на обьект. sm.gif

Естественно, это стандартная реализация инициализации статических объектов функции (а блокировка зависит от того thread safe этот код или нет).

Цитата(brag @ Sep 22 2011, 20:13) *
Ессно тело этих функций лежит на нас.

Это почему это? Компилятор делает это самостоятельно и совершенно прозрачно от программиста, в этом и преимущество.

Цитата(brag @ Sep 22 2011, 20:13) *
И ессно это гемор, проще вызвать init(...) в нужном месте і все

Вообще-то, приведённый код - это реализация паттерна Singleton. Очень хорошая штука к месте. Применяется, главным образом, для борьбы с зависимостью от порядка компиляции объектов. Большого оверхеда не тянет.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 13:32
Сообщение #62


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



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

обьекты, выделены статически, в той или иной мере зависят от состояния ОС, если в них используются ее функции. а большинсво они такие и есть(тк глобальный обьект - должен быть thread-safe обьект) потому так и получается, что в embedded-проекте все оно под одну гребенку для статика. выделять под каждый кусок проекта отдельные секции тоже не в кайф и не всегда катит - у тредов есть shared-memory...

Цитата
256 кБ - весьма приличный объём, если писать код своими руками (а не забить его библиотечными функциями). А по меркам embedded так даже и нифига себе.

да ну. TwoFish,RSA-2048,ECDSA,sha-256,дрова(включая usb-msc,usb-cdc,transflash,всякие там верхнего уровня прибамбасики типа акселерометра с простенькими dsp-алго),всякие там парсеры и немного полезного(не служебного) кода - 110кб сожрало. при чем все ручками, ни единой библиотечной функции,каждый алго вылизивался руками для достижения требуемых условий по производительности. и это нету еще gui с кучей текста(пусть даже на одном инглише,не говоря о 2-3 языках)

Цитата
Rvalue reference - это совсем не те ссылки, которые в нынешнем С++. Это совсем другая штука. Обычные ссылки, кстати, тоже, имхо, зря обделяете вниманием - они в ряде случаев дают более простую семантику и более безопасный код.

разеремся,как поддержка нормальная появится wink.gif

Цитата
init() обладает одним существенным недостатком - нужно не забывать корректировать его при изменениях в совсем других частях программы.

зачем? раз его реализовал, равно как и конструктор и вызываешь где нужно.
Цитата
В общем, это в значительной степени отказ от идеи абстракции (и инкапсуляции) данных в виде законченных объектов, т.е. в некотором роде даунгрейд в С. По мере роста сложности программ, это не добавляет радости.

немного да, помнить все же про обьект(но никак не про внутренности класса,что уже не трогает инкапсуляцию) нужно будет. и вызвать init перед первым его использованием. в embedded надо помніть о гораздо более важных и запутанных вещах, что init никак проблем не создаст. а если его забыть, то прога ляжет сразу и ошибка найдется легко.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Sep 22 2011, 13:37
Сообщение #63


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(brag @ Sep 22 2011, 16:32) *
init никак проблем не создаст. а если его забыть, то прога ляжет сразу и ошибка найдется легко.


Вовсе не обязательно. У нас в одном проекте через месяц программист нашел эту ошибку. А до этого все как-то жило себе и ничего.
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 13:41
Сообщение #64


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Естественно, это стандартная реализация инициализации статических объектов функции (а блокировка зависит от того thread safe этот код или нет).

конечно thread-safe, иначе запарки с конструкторами небыло бы, вернее с необходимостю явного вызова конструктора, переименованного в init(..);.

Цитата
Это почему это? Компилятор делает это самостоятельно и совершенно прозрачно от программиста, в этом и преимущество.

и от куда он знает как у нас реализована блокировак и как ею пользоватся? по моему он никак не догадывается, что у меня есть функции CreateKernelObject(MUTEX_TYPE),OpenMutex(ko),CloseMutex(ko) итд...



Код
Вовсе не обязательно. У нас в одном проекте через месяц программист нашел эту ошибку. А до этого все как-то жило себе и ничего.

Заполните .bss каким-нибдь криптографическим рандомом :D (кроме шуток) и бага вылезет моментально sm.gif

Цитата
Применяется, главным образом, для борьбы с зависимостью от порядка компиляции объектов. Большого оверхеда не тянет.

Чет не вьехал.. что за зависимость от порядка компиляции обьектов и когда она возникает?
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Sep 22 2011, 14:38
Сообщение #65


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Компилятор ничего не знает о потоках, процессах и тд!
Ни PC, ни эмбеддед. Соответственно, никаких блокировок не должен использовать.
Singleton - удобный способ создания одного(И только одного) объекта класса. Если на пальцах - при первом вызове "псевдоконструктора" происходит создание объекта, при последующих - возвращается ссылка на первый объект.
Помимо этого у него ест еще одно полезное свойство - не нужно хранить указатель на объект. Мы его получаем по имени класса.

По поводу порядка инициализации. Порядок инициализации объектов определен лишь в пределах одной единицы трансляции. Соответственно, имя два cpp файла нельзя сказать, статические переменные какого файла будут проинициализированны первыми.
Я с этим борюсь так: у каждого сервиса есть 4 унаследованных метода: Init, Run, Stop, Done. Рассылкой multcast сообщений я их по очереди вызываю. Те сначала вызываются все методы Init, потом все методы Run и тд.
Это вызывается лишь в одном месте программы, тем самым избегаю случая "забывания вызывания Init"

Вот моя реализация синглтона
CODE
///@class TClSingleton
///@brief Use access to object instance.
///After first call Instance() method, create instance of object.
///All next call Instance() method will return pointer to first object
///Typical use:
/// <pre>
///@code
///class SignleObject: public TClSigneton<SingleObject>
///{
/// friend class TClSigneton<SingleObject>;
/// . . . . .
/// protected:
/// SignleObject();
///}
///......
///SignleObject* pclObject_ = SignleObject::Instance(); // Will be created object, or return pointer on early created oblect
///......
///@endcode
/// </pre>
template <class ClSignleObject>
class TClSingleton
{
public:
/// Static method. Will be used in inheritor
/// @return Pointer to object instance
inline static ClSignleObject* Instance();

protected:
/// Protected default constructor
TClSingleton(){}
};

///@brief Realization of instance() method
template <class ClSignleObject>
inline ClSignleObject* TClSingleton<ClSignleObject>::Instance()
{
TClCriticalSection<true> clCS_;

static ClSignleObject* pclInstance_s = new ClSignleObject();
return pclInstance_s;
}


Сообщение отредактировал IgorKossak - Sep 22 2011, 15:56
Причина редактирования: [codebox]
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 15:05
Сообщение #66


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Компилятор ничего не знает о потоках, процессах и тд!
Ни PC, ни эмбеддед. Соответственно, никаких блокировок не должен использовать.

Qt+gcc еще как знает sm.gif

Цитата
Я с этим борюсь так: у каждого сервиса есть 4 унаследованных метода: Init, Run, Stop, Done. Рассылкой multcast сообщений я их по очереди вызываю. Те сначала вызываются все методы Init, потом все методы Run и тд.
Это вызывается лишь в одном месте программы, тем самым избегаю случая "забывания вызывания Init"

зависит от конкретной реализации. в моем случае проще,безопаснее вызвать конструктор явно в нужном месте, чем городить какие-то хитрые конструкции только ради саих этих конструкций и авто-вызова конструктора. забыть вызвать (псевдо)конструктор довольно сложно, тк он асоциирован с подключением конкретного модуля(если я юзаю usb-msc, как же я могу забыть его проинициализироват? а он сам в свою очередь унаследован от usb,и других классов выше, и сам вызовет нужные псевдо-конструкторы по иерархии)
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Sep 22 2011, 15:16
Сообщение #67


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(brag @ Sep 22 2011, 22:05) *
Qt+gcc еще как знает sm.gif

Лично налетал на гонки в синглтоне. Компилятор gcc.
Возможно, я просто не умею его готовить.. Но - осадочек остался. Сейчас только критическая секция.

Цитата(brag @ Sep 22 2011, 22:05) *
зависит от конкретной реализации.

Я бы сказал - зависит от подхода. sm.gif
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Sep 22 2011, 15:21
Сообщение #68


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(brag @ Sep 22 2011, 18:05) *
Qt+gcc еще как знает sm.gif


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


А кто мешает в этом самом нужном месте вызвать:

Код
Class *pAAA = new AAA;


Вызывается сам конструктор, а не какой-то там Init().
Go to the top of the page
 
+Quote Post
777777
сообщение Sep 22 2011, 15:40
Сообщение #69


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(dxp @ Sep 22 2011, 11:25) *
Правда? Т.е. сами по себе классы нафиг не нужны? И перегрузка имён функций/операторов не нужна? И возможность объявлять объекты в любом месте программы не нужна? И наследование (без виртуальных функций) не нужно? И шаблоны не нужны?

Что значит "не нужны"? Что значит "сами по себе"? (почти) всё перечисленное - свойства ООП. Поскольку все это есть в С++, то он является объектно-ориентированным языком.

Цитата(dxp @ Sep 22 2011, 11:25) *
Да будет вам известно, что исходно С++ появился именно как объектный язык, и ОО составляющая была в него добавлена значительно (годы) позже.

Мне кажется при построении этого предложения вы где-то допустиои опечатку.

Цитата(dxp @ Sep 22 2011, 11:25) *
С++ никогда не был чистым ОО языком - ООП в нём - это лишь один (и не очень обширный) из его аспектов.

Изначально он назывался "Си с классами". Потом он получил название С++, а постепенно в него напихали всего, что было модно на текущем этапе развития программирования. Поэтому трудно говорить о том, был ли он когда-нибудь "чистым" ОО языком весьма проблематично.

Цитата(dxp @ Sep 22 2011, 11:25) *
Либо (если не согласны в вышеперечисленным) вы не вполне понимаете, что такое ООП.

Я понимаю, фаллометрия очень важна для посетителей этого форума.
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 16:09
Сообщение #70


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Лично налетал на гонки в синглтоне. Компилятор gcc.
Возможно, я просто не умею его готовить.. Но - осадочек остался. Сейчас только критическая секция.

посему я предпочитаю ручной контроль thread-safety

Цитата
Class *pAAA = new AAA;
Вызывается сам конструктор, а не какой-то там Init().

а реализовывать оператор new кто будет? и какими средствами и зачем, на платформе с 64кб оперативки, половина которой ушла под буфферы и стеки...
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 17:45
Сообщение #71


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



еще вопрос по поводу реюза кода. Как, на пример, в gcc, сделать так, чтобы без модификации исходного кода пихать код и данные в разные секции?
На пример, есть такой класс
Код
class Twofish{
public:
    void Key(const U32 *key32);
    void Encrypt(U32 *oblk32,const U32 *iblk32,U32 nblocks,U32 *iv32);
    void Decrypt(U32 *oblk32,const U32 *iblk32,U32 nblocks,U32 *iv32);
private:
    U32 sboxKey[TWF_KEY_BITS/64];
    struct{
        U32 inWhiten[TWF_BLOCK_BITS/32];   // input/output whitening
        U32 outWhiten[TWF_BLOCK_BITS/32];
        U32 round[2*TWF_ROUNDS];  // round subkeys
    }subKeys;
};

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

скажем есть в одном файле
Twofish twf1;
в другом
Twofish twf2;

надо, чтобы :
код twf1 лежал в секции .text
данные twf1 лежали в секции .bss
код twf2 лежал в секции .text1
данные twf2 лежали в секции .kbss2
при чем, с возможностью наследования
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Sep 22 2011, 18:32
Сообщение #72


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(brag @ Sep 22 2011, 23:45) *
Нужно, его так заточить, чтобы разные экземпляры его обьектов были в разных секциях...

-fdata-sections?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 18:44
Сообщение #73


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



а код? -ffunction-sections , а потом это все вручную собирать в линкер-скрипте...проще уж хедеры править
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 22 2011, 22:54
Сообщение #74


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Реализовал через манипуляцию ld -r, линкер-скрипты, objcopy -G
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Sep 23 2011, 04:30
Сообщение #75


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(brag @ Sep 22 2011, 23:09) *
а реализовывать оператор new кто будет? и какими средствами и зачем, на платформе с 64кб оперативки, половина которой ушла под буфферы и стеки...

Почитайте про "Placement new". Это прояснит многие вопросы, в том числе и про выделение в разных секциях
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Sep 23 2011, 04:49
Сообщение #76


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата(777777 @ Sep 22 2011, 10:49) *
О как! Сильно сказано. Только вот как раз ООП и придумано для того, чтобы можно было не сократить, а полностью ликвидировать утечки памяти - просто нужно тщательно продумать структуру программы и распределение объектов. И выделять память в конструкторе объекта, а удалять в деструкторе. Тогда их не будте никогда. Разве что у тех программистов, которые так и не поняли смысл объектно-ориентированного программирования.

Ах, оставьте свой религиозный пыл для неофитов. sm.gif

Цитата(777777 @ Sep 22 2011, 10:49) *
То есть если в некоем языке есть фича которую вы не понимаете или с которой у вас когда-то были проблемы - то это плохой язык. Вот тот у которого нет такой фичи - хороший.

А теперь прокомментируйте, почему в более современных Java и C# множественное наследование вырезано.

Цитата(777777 @ Sep 22 2011, 10:49) *
Зачем? Вот убей не пойму, почему когда пишут прикладную программу для обычного компьютера, она не требуется, а в микроконтроллерах непременно нужна?

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

Цитата(777777 @ Sep 22 2011, 10:49) *
Динамическое размещение объектов встречается везде, но в C нет средств для аккуратной работы с ними, а в C++ есть.

Нет не везде. У меня в коде не было динамического размещения объектов, пока не пришлось туда запихать lwIP.

Цитата(777777 @ Sep 22 2011, 10:49) *
Да, это серьезный недостаток! На С можно писать и без головы, только... не хотелось бы мне пользоваться таким устройством.

Передергиваете, батенька. Есть такое понятие, как сложность языка. Проще говоря, сколько дров вы наломаете, прежде чем на нем что-то напишете и сколько денег потеряете, разбираясь с багами во время работы готового кода. У C++ сложность, на мой взгляд, самая высокая из современных языков. Даже хаскелл уступает в этом плане.
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 23 2011, 04:50
Сообщение #77


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(777777 @ Sep 22 2011, 22:40) *
Что значит "не нужны"? Что значит "сами по себе"? (почти) всё перечисленное - свойства ООП. Поскольку все это есть в С++, то он является объектно-ориентированным языком.

Как и предполагалось, вы неверно понимаете термин "объектно-ориентированный". Для вас класс С++ - уже ОО, а это не так. ООП - это когда программа построена на основе полиморфного поведения объектов, т.е. когда явно присутствует иерархия классов с виртуальными функциями - методами. Именно это и только это в С++ является объектно-ориентированным подходом. Просто классы даже с наследованием, но без виртуальных функций, не несут ООП, это обычный объектный подход.

Цитата(777777 @ Sep 22 2011, 22:40) *
Я понимаю, фаллометрия очень важна для посетителей этого форума.

С этим вы к себе обратитесь.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
777777
сообщение Sep 23 2011, 05:52
Сообщение #78


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(andrewlekar @ Sep 23 2011, 08:49) *
Ах, оставьте свой религиозный пыл для неофитов. sm.gif

Что значит "религиозный"? Предложение использовать интсрумент только по назначению вы считаете религиозным пылом? Ну да, настоящие пцаны могут и микроскопом гвозди забивать, даже не той стороной.

Цитата(andrewlekar @ Sep 23 2011, 08:49) *
Потому что специфика применения микроконтроллеров, ограниченность ресурсов, как правило отсутствие виртуальной памяти, нехватка времени и людей. Если у вас со всем этим проблем не наблюдается, так можете без адресной арифметики писать код.

Я надеялся увидеть конкретный пример.

Цитата(andrewlekar @ Sep 23 2011, 08:49) *
Передергиваете, батенька. Есть такое понятие, как сложность языка. Проще говоря, сколько дров вы наломаете, прежде чем на нем что-то напишете и сколько денег потеряете, разбираясь с багами во время работы готового кода. У C++ сложность, на мой взгляд, самая высокая из современных языков. Даже хаскелл уступает в этом плане.

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


Цитата(dxp @ Sep 23 2011, 08:50) *
Как и предполагалось, вы неверно понимаете термин "объектно-ориентированный". Для вас класс С++ - уже ОО, а это не так. ООП - это когда программа построена на основе полиморфного поведения объектов, т.е. когда явно присутствует иерархия классов с виртуальными функциями - методами. Именно это и только это в С++ является объектно-ориентированным подходом. Просто классы даже с наследованием, но без виртуальных функций, не несут ООП, это обычный объектный подход.

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

Во-вторых, я даже не представляю где вы выкопали такое определение. Обязательными составными частями ОО всегда считались инкапсуляция, наследование, полиморфизм. Все они есть в С++, о чем еще может быть спор? Или если некая конкретная программа не использует полиморфизм, то она уже не объектно-ориентированная? Но речь вроде бы о языке, а не о программах.

Наконец, последние слова меня привели в полное замешательство: "...без виртуальных функций, не несут ООП, это обычный объектный подход". Это не опечатка? ООП и "объектный подход" чем-то отличаются?
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 23 2011, 07:02
Сообщение #79


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(777777 @ Sep 23 2011, 12:52) *
Во-вторых, я даже не представляю где вы выкопали такое определение. Обязательными составными частями ОО всегда считались инкапсуляция, наследование, полиморфизм.

Только полиморфизм. Динамический. Икапсуляция и абстракция - это объектный подход.

Цитата(777777 @ Sep 23 2011, 12:52) *
Или если некая конкретная программа не использует полиморфизм, то она уже не объектно-ориентированная?

Именно так.

Цитата(777777 @ Sep 23 2011, 12:52) *
ООП и "объектный подход" чем-то отличаются?

Я уже неоднократно и подробно излагал на этом форуме по поводу парадигм программирования, в последний раз не более полугода назад. Повторять лень. Если интересуетесь, поищите по форуму.

Насчёт того, что классы С++ - это уже ООП, это распространённая ошибка. Сравните С++ с true ОО языком - например, со SmallTalk.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 23 2011, 10:15
Сообщение #80


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
очитайте про "Placement new". Это прояснит многие вопросы, в том числе и про выделение в разных секциях

Я их смотрел, когда под плюсы код переводил. Особо от них легче не становится - надо выделять буфферы в статике, не забыть вызвать тот самый new, да и еще с thread safety, скорее всего, возится прийдется. в итоге аналог init(...) получается, только кроме того, надо держать еще указатель на обьект, а это аж 4 байта памяти sm.gif

Цитата
У C++ сложность, на мой взгляд, самая высокая из современных языков. Даже хаскелл уступает в этом плане.

не знаю что вы там сложного нашли.. Классы? так те же структуры. шаблоны? по моему гораздо сложнее их на С реализовывать через убогие макросы. несколько лишних ключевых слов? можно и не запоминать, есть для этоо тетрадка.
Мне после С так вообще такой же, только удобнее. там где были f(&inst) стали inst.f(),
где было куча макросов - стали шаблоны. где были таблицы с функциями - вообще похерились, и генерит их теперь компилятор.
Хотя вру, иногда приходилось писать под Qt, мож по этому мне плюсы не такие уж сложные sm.gif
Go to the top of the page
 
+Quote Post
MALLOY2
сообщение Sep 23 2011, 11:35
Сообщение #81


Знающий
****

Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317



Ссылка в тему С++ & Cortex
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 23 2011, 16:25
Сообщение #82


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Хe, и множественному наследованию (по крайней мере двойному) нашлось применение.

Есть некий класс A. он должен принимать сообщения заданного формата и отправлять ответы тоже заданного формата, но через независящий от класса А и неизвестный ему интерфейс(это может быть sms,sockets,keyboard/display,...)
Код
class A{
private:
     CommIf *commif;
}

Класс CommIf тот самый интерфейс
Код
class CommIf{
public:
    virtual int cmdCbkSend(const void*,U32)=0;
};

Класс а читает с какого-нибудь thread-safe fifo данные, первое слово в этом fifo - у казатель на что-то производное от CommIf.
Код
Fifo.read(&commif,sizeof(commif));

Далее в fifo могут лежать произовльные данные, их можно от туда дочитывать итд. далее,если ему надо отправить ответ - он просто вызывает commif->cmdCbkSend() и кормит ему буффер с данными

Теперь реализация самого интерфейса(будь то смс или соктеы,..)
Код
class Smsiface : public Sms,public CommIf{
public:
   // reimplemented virtuals for CommIf
    int cmdCbkSend(const void *d,U32 n){return sendSms(0,d,n);}
protected: // reimplemented virtuals for Sms
    void smsReceived(int ep,const void *data,U32 len);
};

void Smsiface::smsReceived(int ep,const void *data,U32 len){
    CommIf *commif=static_cast<CommIf*>(this);
    Fifo.write(&commif,sizeof(commif));
}


Все. Смсы,сокеты,итд живут в отдельных тредах независимо друг от друга и от класса A(который тоже живет в отдельном треде).
Подобную хрень я делал и на С, но там запарится можно, пока все отладишь, все хождения по указателям, а на плюсах написал и работает wink.gif
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Sep 23 2011, 17:22
Сообщение #83


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Множественное наследование от интерфейсов разумеется разрешено. А вот множественное наследование реализации запрещено в современных ОО языках. Так что тут вы велосипед изобрели. sm.gif

Цитата
где было куча макросов - стали шаблоны. где были таблицы с функциями - вообще похерились, и генерит их теперь компилятор.

Ну а у меня наоборот: где была невнятная иерархия классов, требующая в дополнение к собственно программе диаграмму зависимостей, появился чистый и понятный код на сях. Где были утечки памяти, вопросы, где вызывать delete, а где delete[], нарушение инкапсуляции (да, в с++ трудно добиться честной инкапсуляции) - всё стало статично и разбито на независимые модули.
Go to the top of the page
 
+Quote Post
BlackHead
сообщение Oct 5 2011, 10:21
Сообщение #84


Участник
*

Группа: Участник
Сообщений: 22
Регистрация: 8-09-08
Пользователь №: 40 058



Вот набрёл на библиотеку С++
http://xpcc.sourceforge.net/api/main.html

Есть кое-что и для ARMов
Go to the top of the page
 
+Quote Post
kikos
сообщение Oct 31 2011, 13:32
Сообщение #85


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 1-02-11
Пользователь №: 62 608



Лет 20 назад один из заказчиков (пожилой американский менеджер) заранее потребовал писать код безо всяких ++. На вопрос почему, сказал, что за жизнь насмотрелся на море плохого С++ кода.
А теперь я могу вслед за ним повторить эту фразу. Более того, почти в 60% случаев кажется , что C++ используют не язык, а как средство самоутверждения.

так что лучше не писать на С++ при создание приложений под ARM... biggrin.gif

Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 31 2011, 13:49
Сообщение #86


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (kikos @ Oct 31 2011, 16:32) *
На вопрос почему, сказал, что за жизнь насмотрелся на море плохого С++ кода.
За жизнь много раз приходилось пробовать невкусный чай (кофе). Так что ж теперь, не пить чай(кофе) совсем?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Forger
сообщение Oct 31 2011, 18:14
Сообщение #87


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(Сергей Борщ @ Oct 31 2011, 17:49) *
За жизнь много раз приходилось пробовать невкусный чай (кофе). Так что ж теперь, не пить чай(кофе) совсем?

+100


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 1 2011, 06:27
Сообщение #88


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(kikos @ Oct 31 2011, 15:32) *
Более того, почти в 60% случаев кажется , что C++ используют не язык, а как средство самоутверждения.
«лет 20 назад» в около микроконтроллерном мире многие похожее и про С говорили.

А сколько тот менеджер в жизни видел некрасивых женщин, у него не интересовались?


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 1 2011, 08:32
Сообщение #89


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Господа критикующие, напоминаю, тема звучит Как писать на С++ при создание приложений под ARM, Примеры
Это означает, что автора интересует ответ на вопрос именно как писать на С++, а вовсе не причины почему этого не следует делать.
Я не призываю переносить религиозную полемику в другую тему ибо поезд уже ушёл и огромное количество разработчиков давно и успешно программируют под МК именно на C++.
И пугать нас своей шоблой пожилых американских менеджеров также не нужно.
Go to the top of the page
 
+Quote Post
brag
сообщение Dec 10 2011, 02:55
Сообщение #90


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Как можно реализовать такую вещ без кривоты, rtti, библиотек:
Код
class Base{
public:
    Base(Base *array){ _a=array;}
    Base *getItem(int n){ return &_a[n]; }
private:
    Base *_a;
};

class Derived: public Base{
public:
    Derived(Derived *array) : Base(array){}
private:
    int other;
};

Derived aaa[]={Derived(0),Derived(0),Derived(0)};
Derived d(aaa);


Ессно, при вызове d.getItem(1) мы получим мусор, вместо &aaa[1]. Сейчас сделал через массив указателей - вместо Base *array передается и хранится Base * const *array, но задолбало лепить эти массивы вручную, а на такое компиллер матерится, типа юзание временного обьекта:
Код
Derived *aaa[]={&Derived(0),&Derived(0),&Derived(0)};
Go to the top of the page
 
+Quote Post
Forger
сообщение Dec 10 2011, 07:09
Сообщение #91


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(brag @ Dec 10 2011, 06:55) *
Как можно реализовать такую вещ без кривоты, rtti, библиотек:

Для полноты картины, расскажите, для чего вам нужна такая конструкция?
Что это на самом деле?


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
neiver
сообщение Dec 10 2011, 07:29
Сообщение #92


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Массив указателей на объекты базового класса - это как раз правильное решение.
А когда вы пытаетесь индексировать массив объектов производного класса
Derived aaa[]={Derived(0),Derived(0),Derived(0)};
как массив объектов базового класса, то происходит "срезка". Объекты базового и производного класса имеют разные размеры.

Цитата
Derived *aaa[]={&Derived(0),&Derived(0),&Derived(0)};
а на такое компиллер матерится, типа юзание временного обьекта

И правильно матерится. На стеке создаются три временных объекта, указатели на них заносятся в массив, после чего эти объекты уничтожаются и их место в стеке освобождается. В результате указатели в массиве указывают куда-то, где раньше был стек и ваши объекты. Сейчас там корректные данные, потом будет мусор.
Правильно создать массив объектов производного типа и массив указателей базового типа...
Go to the top of the page
 
+Quote Post
brag
сообщение Dec 10 2011, 15:37
Сообщение #93


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Для полноты картины, расскажите, для чего вам нужна такая конструкция?
Что это на самом деле?


Это для построения gui. вот пример использования:
Код
....

static MenuItem* const settingsItemsList[]={
    &settingsItems[0],&settingsItems[1],
    &settingsItems[2],&settingsItems[3],
    &settingsItems[4],&settingsItems[5],
    &settingsItems[6],&settingsItems[7]
};
static Menu settingsMenu(Rect(0,8,96,56),0,settingsItemsList,sizeof(settingsItemsList)/sizeof(MenuItem*));

static MenuItem mainItems[]={
    MenuItem(0,"Normal",&normalMenu),
    MenuItem(0,"Professional",&proMenu),
    MenuItem(0,"Settings",&settingsMenu),
};
static MenuItem* const mainItemsList[]={ &mainItems[0],&mainItems[1],&mainItems[2] };
static Menu mainMenu(Rect(0,8,96,56),0,mainItemsList,sizeof(mainItemsList)/sizeof(MenuItem*));


Сам конструкторы выглядят так:
Код
class Menu: public Widget{
public:
    Menu(const Rect &geom,Widget *parent=0,MenuItem* const *children=0,int nchild=0);
...

Код
class MenuItem: public Widget{
public:
    MenuItem(Menu *parent=0,const char *text=0,Menu *target=0);
...

Код
class Widget : public PaintDevice{
public:
    Widget(Widget *parent=0,Widget* const *children=0,int nchild=0);
....


Цитата
Массив указателей на объекты базового класса - это как раз правильное решение.

правильное, только вот ни препроцессор, ни самя язык похоже не позволяет его создать "автоматом", в отличия, скажем, массива указателей на строки:
const char* const stringptrs[]={"kolbasa1","kolbasa2","kolbasa3"};
вот такое хотелось бы иметь и для обьектов...

Цитата
Правильно создать массив объектов производного типа и массив указателей базового типа...

массив указателей должен тоже быть производного типа, тк он передается производному классу сначала:
Menu(const Rect &geom,Widget *parent=0,MenuItem* const *children=0,int nchild=0);
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 10 2011, 17:39
Сообщение #94


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(brag @ Dec 10 2011, 22:37) *
массив указателей должен тоже быть производного типа, тк он передается производному классу сначала:
Menu(const Rect &geom,Widget *parent=0,MenuItem* const *children=0,int nchild=0);

Если я правильно понял, что требуется работа с коллекцией объектов, то я для таких целей юзаю stl::list<Widget*>. Да, там будет аллокация памяти, но размер ноды небольшой (три указателя) и траблов с фрагментацией в этом случае, вроде, не ожидается.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
brag
сообщение Dec 10 2011, 18:11
Сообщение #95


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Если я правильно понял, что требуется работа с коллекцией объектов, то я для таких целей юзаю stl::list<Widget*>. Да, там будет аллокация памяти, но размер ноды небольшой (три указателя) и траблов с фрагментацией в этом случае, вроде, не ожидается.

stl не канает, из доступных вещей есть только проц, голый компилятор и моск.
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 10 2011, 21:44
Сообщение #96


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(brag @ Dec 11 2011, 01:11) *
stl не канает, из доступных вещей есть только проц, голый компилятор и моск.

О как! А куда ж стандартная библиотека-то делась? Компилятор один, что-ли, присутствует? sm.gif К тому же, stl - открытая вещь, можно взять и отдельно. Правда, может потребоваться доводка напильником. А может и не потребоваться.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
brag
сообщение Dec 10 2011, 22:59
Сообщение #97


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



да просто проект такой, что проще свое написать, чем прикручивать что-то туда и потом парицца с синхронизацией, гонками итп...
Go to the top of the page
 
+Quote Post
kan35
сообщение Dec 11 2011, 09:52
Сообщение #98


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Писать на С++ под ARM точно так же как на любую другую архитектуру. О чем тут вообще можно рассусолить на 7 страниц?
Go to the top of the page
 
+Quote Post
alx2
сообщение Dec 11 2011, 10:37
Сообщение #99


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(brag @ Dec 10 2011, 07:55) *
Как можно реализовать такую вещ без кривоты, rtti, библиотек:

Наверное как-то так:
CODE
template <typename T>
class Base{
public:
Base() : _a(NULL) {}
Base(T *array) : _a(array) {}
T *getItem(int n) const { return &_a[n]; }
private:
T * _a;
};

class Derived: public Base<Derived>{
public:
Derived() {}
Derived(Derived *array) : Base<Derived>(array){}
private:
int other;
};

int main()
{
Derived array[3];
Derived d(array);
return printf("%p = %p\n", d.getItem(1), &array[1]);
}

Хотя лучше, как Вам уже посоветовали, использовать stl.
Цитата(brag @ Dec 11 2011, 03:59) *
да просто проект такой, что проще свое написать, чем прикручивать что-то туда и потом парицца с синхронизацией, гонками итп...

Если вы способны писать код классом выше чем годами и тысячами людей проверенные реализации stl, почему Вы задаете такие вопросы? sm.gif
Если Вы используете многопоточность, неиспользование stl не гарантирует отсутствие в вашем коде гонок и не избавляет от необходимости "парицца с синхронизацией". Также как использование stl не способствует появлению гонок.
Синхронизация потоков в обоих случаях остается вашей заботой.

Сообщение отредактировал alx2 - Dec 11 2011, 11:19


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
brag
сообщение Dec 11 2011, 13:32
Сообщение #100


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



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

Цитата
Если вы способны писать код классом выше чем годами и тысячами людей проверенные реализации stl, почему Вы задаете такие вопросы?

Никто этого не говорил, просто так проще, во первых. в системе совсем иные механизмы распределения памяти(скажем, аналога malloc нету) и других ресурсов, что несовместимо с stl, по крайней мере с ее частями....
на основе динамики (stl::list<Widget*>) не идет.
И на основе статики тоже - памяти мало, надо экономить. Константый массив указателей в flash - самое оно, создавать бы его еще красиво...
Go to the top of the page
 
+Quote Post

13 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 03:29
Рейтинг@Mail.ru


Страница сгенерированна за 0.02856 секунд с 7
ELECTRONIX ©2004-2016