|
Помогите разобраться с классами С++, вопрос с построением иерархии |
|
|
|
Apr 23 2007, 09:57
|

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

|
Добрый день! Я занимаюсь написанием графического интерфейса для LCD монитора на 16-разрядном микроконтроллере XC167. Для графики пытаюсь использовать ООП. Опыт работы с ООП совсем небольшой. У меня есть некоторые недопонимания с построением иерархии классов. Например, хотелось бы создать класс TFont. От него наследовать TChar (все что касается отображения символов). Далее от TChar - TString. Но с другой стороны рисования символа состоит из рисования точек. А все, что связано с точками (Line, Circle ...) растет от класса TPoint. Как тут быть? Ведь TFont совсем не связан логически с TPoint (как мне кажется). Использовать множественное наследование? пересмотреть TFont - TChar? Отказаться от связи TChar с классами иерархии TPoint? Пожалуйста пролейте свет на этот вопрос. P.S. Не могли бы вы посоветовать мне какие-нибудь книги или статьи с жизненными примерами ООП. А то, в основном, все примеры которые мне попадались какие-то слишком академичные. Заранее благодарен!
|
|
|
|
|
 |
Ответов
(1 - 12)
|
Apr 23 2007, 10:39
|

Частый гость
 
Группа: Новичок
Сообщений: 153
Регистрация: 29-03-07
Из: Саратов
Пользователь №: 26 613

|
Я бы на вашем месте пошел по такому пути... Поставил бы на компьютере C++Builder, затем посмотрел, как там организована иерархия классов, а затем попытался бы портировать это дело в ту версию С++, которую использую... Кстати, если я не ошибаюсь, В Билдере класс TString никак не связан с выдачей инфомации на экран... Это чуть ли не просто нуль-теминальная строка (В С++ изначально есть работа только с символами char, а строка символов - это одномерный массив, но работать так не очень удобно, поэтому есть класс TString... Вывод символьных данных и графической информации отличается... Нам нужно будет создать два разных объекта... А в общем - покопайтесь сами - найдете много интересного, хотя Некоторые вещи скрыты архитектурой Windows, но вам необходима именно иерархия объектов...
--------------------
!!! All you need is LOVE !!!
|
|
|
|
|
Apr 23 2007, 10:57
|

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

|
Цитата(Freeze Anti @ Apr 23 2007, 11:39)  Я бы на вашем месте пошел по такому пути... Поставил бы на компьютере C++Builder, затем посмотрел, как там организована иерархия классов, а затем попытался бы портировать это дело в ту версию С++, которую использую... Кстати, если я не ошибаюсь, В Билдере класс TString никак не связан с выдачей инфомации на экран... Это чуть ли не просто нуль-теминальная строка (В С++ изначально есть работа только с символами char, а строка символов - это одномерный массив, но работать так не очень удобно, поэтому есть класс TString... Вывод символьных данных и графической информации отличается... Нам нужно будет создать два разных объекта... А в общем - покопайтесь сами - найдете много интересного, хотя Некоторые вещи скрыты архитектурой Windows, но вам необходима именно иерархия объектов... Вы правы TString на PC имеет несколько другой смысл и в действительности не связан с выводом на экран. Я же думал этот класс заточить под вывод, с виртуальными методами родителей типа MoveTO(для бегущей строки) и.т.д. Но вот настройка самого шрифта(тип, размер...) как-то не вяжется с классовой структурой рисования. Насчет С++Builder, я думаю так: В нем реализованы классы, которые в качестве методов используют функции Win32API, а этот интерфейс не объектный. Вот если бы он был объектным - мне бы оттуда структуру тянуть стоило-бы. А BCB - надстройка. Насколько мне помнится(я имел раньше дело с BCB), в нем с TObject пляшут в смысле графики. Но все-же, в BCB глянуть стоит конечно...
|
|
|
|
|
Apr 23 2007, 11:12
|

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

|
Цитата(Freeze Anti @ Apr 23 2007, 14:39)  Я бы на вашем месте пошел по такому пути... Поставил бы на компьютере C++Builder, затем посмотрел, как там организована иерархия классов, а затем попытался бы портировать это дело в ту версию С++, которую использую... Вот ни в коем случае не надо для этого использовать CBuilder - там весь ГУИ основан на VCL, которая заимствована из Delphi и, соответственно, реализована на борландовском Паскале (если это можно так назвать  ). Включая ту же TString - компонент VCL. VCL никакого отношения к языку С++ не имеет. Правильная подсказка - взять хорошую книжку по языку и по ООП (см выше).
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 26 2007, 10:58
|
Участник

Группа: Новичок
Сообщений: 25
Регистрация: 24-03-07
Пользователь №: 26 466

|
Извиняюсь за глупый вопрос. Но разве ООП и микроконтроллеры дружат? Я думал, что для микроконтроллеров существуют максимум компиляторы С, но никак ни С++?
|
|
|
|
|
Apr 27 2007, 13:37
|

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

|
Цитата(Bogatyr @ Apr 26 2007, 11:58)  Извиняюсь за глупый вопрос. Но разве ООП и микроконтроллеры дружат? Я думал, что для микроконтроллеров существуют максимум компиляторы С, но никак ни С++? Микроконтроллеры бывают разные! Не хочу поднимать тему сравнения микроконтроллеров и микропроцессоров, но какая разница между вашим домашним компьютером и МК? Непроизводительные издержки С++ в основном в виртуальном механизме. Мощный МК их способен с лихвой покрыть!
|
|
|
|
|
Apr 27 2007, 14:49
|

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

|
Цитата(Bogatyr @ Apr 26 2007, 14:58)  Извиняюсь за глупый вопрос. Но разве ООП и микроконтроллеры дружат? Я думал, что для микроконтроллеров существуют максимум компиляторы С, но никак ни С++? Вполне дружат. А что этому мешает? В чем С++ принципиально более требователен к ресурсам по сравнению с С при реализации той же функциональности? Итого, С++ есть даже для 8-битного AVR и прекрасно работает. Конечно, там не полный перечень фич С++ поддерживается - не поддерживаются тяжелые и реально ненужные механизмы языка - исключения, RTTI. Множественное наследование также не поддерижвается, но это, видимо, от того, что не очень надо. Основные возможности - классы, перегрузка функций и операторов, шаблоны и т.д., все это есть и замечательно работает. Цитата(Legotron @ Apr 27 2007, 17:37)  Непроизводительные издержки С++ в основном в виртуальном механизме. Тут есть некий оверхед на организацию механизма, но он объективно необходим. Ведь для оценки оверхеда (и вообще, оверхед ли это) надо сравнить с реализацией тоже функциональности традиционными (Сишными) средствами. Уверяю Вас, что руками лучше сделать вряд ли получится. Цитата(Legotron @ Apr 27 2007, 17:37)  Мощный МК их способен с лихвой покрыть! И не мощный тоже.  То же AVR прекрасно с этим справляется.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 27 2007, 15:57
|

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

|
Цитата(dxp @ Apr 27 2007, 15:49)  Тут есть некий оверхед на организацию механизма, но он объективно необходим. Ведь для оценки оверхеда (и вообще, оверхед ли это) надо сравнить с реализацией тоже функциональности традиционными (Сишными) средствами. Уверяю Вас, что руками лучше сделать вряд ли получится. Абсолютно с вами согласен. Но всё-таки можно и switch - case конструкцией обойтись(в некоторых случаях). Хотя по сравнению с механизмом полиморфизма она кажется несовершенной. Неболшой оффтопик: У меня возник такой вопрос: Есть класс А. Он наследутся классом В. В обеих классах есть виртуальная функция Draw. Код class A { ... virtual void Draw(); ... }; class B : public A { ... virtual void Draw(); ... };
A *PObjA; // указатель на базовый класс B ObjB; // Создан объект класса В
void * Ptr;
Ptr = (A *)PObjA; // может лишнее Ptr = &ObjB; Ptr->Draw(); // будет ли вызвана ф-ция Draw класса В? Можно ли вообще так сделать? Этот вопрос возник из желания сделать универсальный связанный список с полем Item типа void * для любых объектов?
|
|
|
|
|
Apr 27 2007, 16:56
|

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

|
Цитата(Legotron @ Apr 27 2007, 19:57)  Абсолютно с вами согласен. Но всё-таки можно и switch - case конструкцией обойтись(в некоторых случаях). Хотя по сравнению с механизмом полиморфизма она кажется несовершенной. Ну, реализовать функциональность можно разными путями, но switch/case далеко не всегда предоставляют адекватную замену. Например, можно поставлять библиотеку с функциями, но саму реализацию скрыть внутри. А пользователь вызывает вроде одну и ту же функцию (виртуальную), а реализация может быть разной. По этому принципу, например, строятся СОМ интерфейсы в винде. Цитата(Legotron @ Apr 27 2007, 19:57)  Есть класс А. Он наследутся классом В. В обеих классах есть виртуальная функция Draw. Код class A { ... virtual void Draw(); ... }; class B : public A { ... virtual void Draw(); ... };
A *PObjA; // указатель на базовый класс B ObjB; // Создан объект класса В
void * Ptr;
Ptr = (A *)PObjA; // может лишнее Ptr = &ObjB; Ptr->Draw(); // будет ли вызвана ф-ция Draw класса В? Можно ли вообще так сделать? Этот вопрос возник из желания сделать универсальный связанный список с полем Item типа void * для любых объектов?  "Ptr = (A *)PObjA; // может лишнее" - однозначно лишнее, хотя это ничего не меняет.  Работать не будет. Ptr имеет тип void * - это просто хранилище для адресов, а чтобы можно было работать с объектом класса, указатель на него должен "знать" о строении (структуре) класса. Вот A *pA; B *pB; тут pA "знает" все о классе А, а pB - все о классе В. Поэтому будет работать вызов: A *p = &ObjB; p->Draw(); Вообще, использование void * и ручных преобразований типов - есть плохая практика, старайтесь ее избегать. Существует очень ограниченное количество случаев, где без этого не обойтись, но их стараются "обернуть", чтобы это не лежало на поверхности. Что касается универсальности в отношении разных типов, то, возможно, Вам помогут шаблоны. Т.е. тип объекта задавать как параметр шаблона.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 27 2007, 20:06
|

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

|
Цитата(dxp @ Apr 27 2007, 17:56)  Вообще, использование void * и ручных преобразований типов - есть плохая практика, старайтесь ее избегать. Существует очень ограниченное количество случаев, где без этого не обойтись, но их стараются "обернуть", чтобы это не лежало на поверхности. Да безусловно эти вещи потенциально опасны! Но как мне кажется, с ними порой получается изящней. А то ведь строгое соответствие типов - это Паскаль. Там компилятор 100 раз обругает, чтобы ни-ни... Ну, ничего не попишеш - дисциплина важная вешь!  Думаю, что я еще ни разу хорошенько не погорел на этом, поэтому люблю поизящнее. А мастерство, это когда практично! Цитата(dxp @ Apr 27 2007, 17:56)  Что касается универсальности в отношении разных типов, то, возможно, Вам помогут шаблоны. Т.е. тип объекта задавать как параметр шаблона. Спасибо за ценный совет, я думаю, что шаблоны это как раз то, что мне надо!
|
|
|
|
|
Oct 29 2007, 16:32
|
Группа: Новичок
Сообщений: 11
Регистрация: 29-10-07
Пользователь №: 31 841

|
а что если зделать так как в той же винде: если ЛЦД графический то создать класс который реализует так наз. "контекст устройства" а уже потом создавать объекты по типу виндовых GDI Object-ов таких как шрифты или графические примитивы, кисти которые уже будут рисовать в вашем контексте....
|
|
|
|
|
Oct 30 2007, 11:07
|
Группа: Новичок
Сообщений: 3
Регистрация: 24-10-07
Пользователь №: 31 684

|
Цитата(Legotron @ Apr 27 2007, 18:57)  Этот вопрос возник из желания сделать универсальный связанный список с полем Item типа void * для любых объектов?  В качестве итема может выступать указатель на самый базовый класс (в данном случае class A), а инициализировать его можно в зависимости от надобности либо объектом классса B либо A (либо C или D если Вы их позже создадите, и унаследуете от наследника A или самого А). То есть в результате у Вас будет список из элементов с полем A *item, с которым можно делать: item = new A; или item = new B; после чего, вызывая item->draw() будет вызываться метод draw() класса A или B соответственно.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|