Stas633 0 7 ноября, 2008 Опубликовано 7 ноября, 2008 · Жалоба ... Спасибо. Согласен... Наследование для решения вопроса доступа - это, как минимум, не экономно. ... Если говорить по теме, то вопрос доступа решил так, как рекомендовал dxp. А именно: - каждый объект "размещен" в своей "единице компиляции" (ЕдКомп) /связка файлов, например, One.h и One.cpp/ (так делал и раньше); - член класса /TOne mTOne;/ объявляется теперь в TOne.cpp, а не в main.cpp как раньше; - а для возможности использования функций (свойств) TOne, там где нужно, mTOne объявляется с квалификатором extern. ... файл One.h ... class TOne { ... public: void FuncOne(void); ... } ... файл One.cpp ... TOne mTOne; .... void FuncOne(void) { } ... файл Two.h ... class TTwo { ... public: void FuncTwo(void); ... } ... файл Two.cpp .... #include "One.h" TTwo mTTwo; extern TOne mTOne; .... void FuncTwo(void) { ... mTOne.FuncOne(); ... } На мой взгляд, наиболее простой и понятный способ. А если говорить не совсем по теме, то главная проблема ("разруха" в первоисточнике) "...в головах, а не в клозетах..." (с) Нельзя заниматься ООП оперируя процедурами. Как только приходишь к пониманию "объекта", так все очень упрощается. И "создание" (представление) модели программы, и понимание взаимоотношений между разными частями этой программы. Не буду пересказывать написанное Гради Бучем (и про мыслительный процесс человека в повседневной жизни, и про количество абстракций, с которыми человек способен работать одновременно, и т.д.), но, на мой взгляд, достаточно прочесть главу "1.2. Структура сложных систем" и вопросов о полезности и естественности перехода к ООП не остается. Мир вокруг нас состоит из Объектов, а не из Процедур. И живем мы, используя Объекты и их какие-то свойсва (Процедуры), а не Процедуры каких-то Объектов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Stas633 0 21 ноября, 2008 Опубликовано 21 ноября, 2008 · Жалоба Поиск "оптимального" решения продолжается.... Позволю себе напомнить "проблему"... Есть некий объект (класс), допустим, модуль отладки (DBGU) через UART. Естественно, объект может (и должен) инициализироваться, принимать и передавать инфу, и др. Свойства (функции, методы....) этого объекта (класса), ес-но должны быть доступны другим, если не сказать всем остальным, объектам. При этом, все остальные обекты могут находиться в "родительско-наследственных" отношениях. Как получить доступ к функциям DBGU? То, что использовать наследование DBGU для получения доступа к его свойсвам, не рационально описано выше в теме. Содание класса TDBGU как виртуального гарантирует, что при косвенном ("вложенном") наследовании "верхних" классов не будет создано двух копий TDBGU. А если virtual TDBGU наследуется двумя "отдельными" (разными, самостоятельными...) классами, то для каждого будет создана своя копия TDBGU... Или я не прав? И что вообще означает "производный класс содержит копию базового класса"? Про "создание" копий переменных базового класса при наследовании понятно, а как наследуются функции? Просмотр "откомпилированного" кода и здравый смысл подсказывает, что функции наследуются "беззатратно". Но если это так, то при условии остутсвия переменных в базовом классе его копия ничего не "весит"? Объявление глобального объекта mDBGU с использованием там "где нужно" конструкции extern ... mDBGU так же не лишено недостатков (как способ). Во-первых, глобальный объект "размещается" в "глобальной" области, при этом размещается "раз и навегда". Ну и, во-вторых, нарушается один из первейших принципов ООП - инкапсуляция. (Второе, конечно, относится скорее к стилю программирования нежели к "ошибкам", но если не выполнять правил, то зачем переходить на CPP?). Кстати, натолкнуло на эту мысль упорное "нежелание" IAR инициализировать глобальные объекты при startup'e. Далее... friend... ЧтО позволяет "делать" функция или класс , объявленные в другом как friend? Использовать функции (свойства) friend класса? НО! только через инициализированный объект mDBGU! А как быть если этот объект еще не "создан" или не "виден"?.... (И вообще, насколько я понял, конструкция friend "нужна" для доступа к privat переменным friend класса.) Остается доступ к свойствам (функциям) DBGU через их объявление с квалиф. static. Ранее я писал, что "...static гарантирует, что будет создана только одна копия этого элемента...". Это справедливо, но только для переменных (может я ошибаюсь?). Для функций же это квалификатор "устанавливает" глобальную "видимость" и "доступность" даже до инициализации объекта mDBGU..и только. Таким образом, объявив ф-цию как в staticах, можно ее "использовать" где угодно, конечно предварительно "показав" ее (класс) через #include. Это очень "смахивает" на Си-подход, но лучшего в голову не приходит... Хотя спинной мозг "подсказывает", что не все так однозначно... :) Просвятите, плз. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bookevg 0 22 ноября, 2008 Опубликовано 22 ноября, 2008 (изменено) · Жалоба Поиск "оптимального" решения продолжается.... Позволю себе напомнить "проблему"... Есть некий объект (класс), допустим, модуль отладки (DBGU) через UART. Естественно, объект может (и должен) инициализироваться, принимать и передавать инфу, и др. Свойства (функции, методы....) этого объекта (класса), ес-но должны быть доступны другим, если не сказать всем остальным, объектам. При этом, все остальные обекты могут находиться в "родительско-наследственных" отношениях. Как получить доступ к функциям DBGU? Я так понимаю различные классы будут обращаться к DBGU - т.о. надо сделать систему доступа к общему ресурсу или создать список заданий для DBGU То, что использовать наследование DBGU для получения доступа к его свойсвам, не рационально описано выше в теме. Содание класса TDBGU как виртуального гарантирует, что при косвенном ("вложенном") наследовании "верхних" классов не будет создано двух копий TDBGU. А если virtual TDBGU наследуется двумя "отдельными" (разными, самостоятельными...) классами, то для каждого будет создана своя копия TDBGU... Или я не прав? И что вообще означает "производный класс содержит копию базового класса"? Про "создание" копий переменных базового класса при наследовании понятно, а как наследуются функции? Просмотр "откомпилированного" кода и здравый смысл подсказывает, что функции наследуются "беззатратно". Но если это так, то при условии остутсвия переменных в базовом классе его копия ничего не "весит"? Мне кажется, что вы неправильно трактуете суть полиморфизма - советую прочитать Дж.Либерти - Освой С++ за 21 день. Попробую автора процитировать: Можно объвить множество окон разных типов, включая диалоговые, прокручиваемые и поля списков и т.д.), после чего создавать их в программе с помощью единственного виртуального метода draw(). Создав указатель на базовое окно и присваивая этому указателю адреса объектов производных классов, можно обращаться к методу draw() независимо от того, с каким из объектов в данный момент связан указатель. Причем всегда будет вызываться вариант метода, специфичный для класса выбранного объекта. Объявление глобального объекта mDBGU с использованием там "где нужно" конструкции extern ... mDBGU так же не лишено недостатков (как способ). Во-первых, глобальный объект "размещается" в "глобальной" области, при этом размещается "раз и навегда". А как по вашему работают cin и cout - ведь вы ведь нигде от них не наследуетесь, а они отвечают за ввод и вывод информации Ну и, во-вторых, нарушается один из первейших принципов ООП - инкапсуляция. (Второе, конечно, относится скорее к стилю программирования нежели к "ошибкам", но если не выполнять правил, то зачем переходить на CPP?). Ничего не нарушается. Кстати, натолкнуло на эту мысль упорное "нежелание" IAR инициализировать глобальные объекты при startup'e. До входа в main() все глобальные классы проинициализированы, т.е. вызваны все конструкторы. Далее... friend... ЧтО позволяет "делать" функция или класс , объявленные в другом как friend? Использовать функции (свойства) friend класса? НО! только через инициализированный объект mDBGU! А как быть если этот объект еще не "создан" или не "виден"?.... (И вообще, насколько я понял, конструкция friend "нужна" для доступа к privat переменным friend класса.) Вообще никогда friend-ом не пользуюсь Остается доступ к свойствам (функциям) DBGU через их объявление с квалиф. static. Ранее я писал, что "...static гарантирует, что будет создана только одна копия этого элемента...". Это справедливо, но только для переменных (может я ошибаюсь?). Для функций же это квалификатор "устанавливает" глобальную "видимость" и "доступность" даже до инициализации объекта mDBGU..и только. Таким образом, объявив ф-цию как в staticах, можно ее "использовать" где угодно, конечно предварительно "показав" ее (класс) через #include. Это очень "смахивает" на Си-подход, но лучшего в голову не приходит... Хотя спинной мозг "подсказывает", что не все так однозначно... :) Static переменные и методы нужны для действий, которые оперируют общими ресурсами для всех экземпляров класса. Также можно создавать только static классы - что я очень часто и использую - на производительность это никак не сказывается, т.к. компилятор все это сводит к С-реализации Изменено 22 ноября, 2008 пользователем bookevg Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Stas633 0 22 ноября, 2008 Опубликовано 22 ноября, 2008 · Жалоба Я так понимаю различные классы будут обращаться к DBGU - т.о. надо сделать систему доступа к общему ресурсу или создать список заданий для DBGU Совершенно верно. Только ЧТО делать понятно, а вот что на счет того КАК делать? Мне кажется, что вы неправильно трактуете суть полиморфизма - советую прочитать Дж.Либерти - Освой С++ за 21 день. Попробую автора процитировать: Можно объвить множество окон разных типов, включая диалоговые, прокручиваемые и поля списков и т.д.), после чего создавать их в программе с помощью единственного виртуального метода draw(). Создав указатель на базовое окно и присваивая этому указателю адреса объектов производных классов, можно обращаться к методу draw() независимо от того, с каким из объектов в данный момент связан указатель. Причем всегда будет вызываться вариант метода, специфичный для класса выбранного объекта. Не соглашусь с Вами. В приведенной цитате речь идет о методах, т.е. виртуальных функциях . Которые естественно должны иметь свое "наполнение" в производных классах. Но я рассуждал не о наследовании виртуальных функций и полиформизме, а о наследовании virtual класса класса как virtual. Как я понимаю, виртуальный класс вовсе не "обязан" содержать виртуальные функции. Более того, виртульные функции можно создавать только в абстактнх классах. То есть объектов таких классов создано быть не может. Просто "не получится". Не так ли? А как по вашему работают cin и cout - ведь вы ведь нигде от них не наследуетесь, а они отвечают за ввод и вывод информации Извините, не понял к чему это... Я имел ввиду нецелесообразность обявления global объектов, если есть возможность сделать их локальными. Ничего не нарушается. Спорно. Если объект объявляется/выносится за пределы своего "ареала обитания", то разве это соответсвует принципу encapsulation? Зачем в список фруктовых деревьев сада вносить функцию измерения размера косточки плода? Ведь к этой функции все равно придется обращаться, как минимум, через Плод. (На точности примера не настаиваю) До входа в main() все глобальные классы проинициализированы, т.е. вызваны все конструкторы. Так должно быть, но не всегда так есть. "Встроенный" Cstartup.s79 для IARARM НЕ СОДЕРЖИТ вызовов конструкторов до входа в main(). На форуме упомянуты способы введения такой инициализации (в частности, Сергеем Борщем). Вообще никогда friend-ом не пользуюсь А почему? Static переменные и методы нужны для действий, которые оперируют общими ресурсами для всех экземпляров класса. Т.е. данными? Также можно создавать только static классы - что я очень часто и использую - на производительность это никак не сказывается, т.к. компилятор все это сводит к С-реализации Другими словами, если не смог (к Вам никакого отношения не имеет!) написать на С++ используй static и пиши как на С... :05: ... И все-таки, если класс не содержит ресурсов (переменных, данных), то будет ли формироваться избыточный код при его "многократном" наследовании? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bookevg 0 24 ноября, 2008 Опубликовано 24 ноября, 2008 · Жалоба Совершенно верно. Только ЧТО делать понятно, а вот что на счет того КАК делать? Не соглашусь с Вами. В приведенной цитате речь идет о методах, т.е. виртуальных функциях . Которые естественно должны иметь свое "наполнение" в производных классах. Но я рассуждал не о наследовании виртуальных функций и полиформизме, а о наследовании virtual класса класса как virtual. Зачем нужно, чтобы весь класс был виртуальным - надо только, чтобы методы были и этого достаточно Как я понимаю, виртуальный класс вовсе не "обязан" содержать виртуальные функции. А зачем тогда он нужен - виртуальность нужна как раз только для методов Более того, виртульные функции можно создавать только в абстактнх классах. То есть объектов таких классов создано быть не может. Просто "не получится". Не так ли? Еще как можно использовать - т.е. объявил класс СTimers1 как обычно, создал вирт.метод СTimers1::Update, затем породил класс СTimers2 от СTimers1 и переписал СTimers1::Update и создал два экземляра СTimers1 Timers1; и СTimers2 Timers2 и работаешь с ними. Извините, не понял к чему это... Я имел ввиду нецелесообразность обявления global объектов, если есть возможность сделать их локальными. Я как понял вашу задачу: вы хотите, чтобы другие объекты через экземпляр класса DBGU общались с внешним миром - но ведь на PC-машинах все наши объекты общаются с внешним миром или через cin/cout или GUI Спорно. Если объект объявляется/выносится за пределы своего "ареала обитания", то разве это соответсвует принципу encapsulation? Зачем в список фруктовых деревьев сада вносить функцию измерения размера косточки плода? Ведь к этой функции все равно придется обращаться, как минимум, через Плод. (На точности примера не настаиваю) А зачем почти что всем животным воздух? Так должно быть, но не всегда так есть. "Встроенный" Cstartup.s79 для IARARM НЕ СОДЕРЖИТ вызовов конструкторов до входа в main(). На форуме упомянуты способы введения такой инициализации (в частности, Сергеем Борщем). Незамечал, я обычно всегда делаю свой Cstartup.s79, так что мог и ошибиться, но вроде еще с AVR глобаль.объекты инициализировал компилятор - даже пришлось убрать инициализацию из конструкторов, чтоб все происходило по порядку определяемому мною А почему? Пока нужды не возникало использование friend, если и порывался. то находил другие пути выхода из ситуации, да и не все embedded компиляторы поддерживали это лет 4-6 назад. Т.е. данными? Необязательно, м.б. и общие действия, но в принципе все равно все сводится к данным Другими словами, если не смог (к Вам никакого отношения не имеет!) написать на С++ используй static и пиши как на С... :05: Все проекты разрабатываются в Microsoft Visual Studio - при оформлении классом одновременно улучшается читабельность кода ... И все-таки, если класс не содержит ресурсов (переменных, данных), то будет ли формироваться избыточный код при его "многократном" наследовании? Зависит от умности компилятора и линкера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Stas633 0 24 ноября, 2008 Опубликовано 24 ноября, 2008 · Жалоба Ув. bookevg, Вы, безусловно, во многом правы! :) (Мне кажется, что понятия виртуальный класс не существует вовсе. Абстрактный, т.е. не имеющий объектов/членов - да, такое понятие/механизм описан. Другое дело, если отнаследовать любой класс как virtual, для исключения создания более одной копии при косвенном наследовании, - пожалуйста. Да и к полиформизму наследование класса с идентификатором virtual отношения не имеет. Поправьте, если ошибаюсь.) Спасибо Вам за участие. :a14: Свой выбор "оптимального" способа я сделал. :) Правда, только благодаря помощи dxp. :) Не буду коверкать "первоисточник" - завтра вставлю цитатой... Смысл сказанного прост до банальности. :) С++ - язык гибридный, он сочетает разные стили программирования - и процедурный (как в голом С), и объектный (на классах), и ООП (на иерархиях классов с полиморфизмом). Можно использовать любые средства в любых сочетаниях - какие на задачу ложатся, те и использовать. Не нужно пытаться применять ООП там, где все легко и управляемо делается процедурным способом. Но там, где ООП к месту, его надо применять, не колеблясь. :) Зачем из пушки стрелять по воробьям? Если, как в моем случае, из высокоуровнего класса вызывается функция низкоуровнего кл., при этом вызываемая функция просто знает/умеет дернуть ногой, вывести/принять данные по шине, и, при этом, ни как не "общается" ни с высокоуровневым классом, ни в низкоур-вом ничего не меняет, то зачем наследовать низ.ур в выс.ур? static и все! :) Я же, в желании "прочно" перейти к С++ программированию, считал использование static C-конструкцией, "недостойной" С++ программирования. :05: А вот если при вызове функций происходит взаимодействие с элементами классов, ну, например, несколько программных модулей выводят данные по одной и той же шине, и необходимо знать сколько байт данных передано кажным модулем, то без наследования тут никуда. Для каждого модуля должна быть своя копия счетчика, инкрементируемая вызываемой функцией... Ну и т.д. (Конечно этот пример можно "решить" и с использованием static, например добавляя к входным параметрам функции номер модуля... Но эффективность, понятность кода будет "никакой".) .... В общем, все как обычно - нужно делом, не важно каким, или заниматься всерьез, или не заниматься вообще. Нельзя изучить синтаксис С++ и заявить: "А я теперь умею программировать на С++!" .... Кстати, использование static вместо наследования сокращает программный код и время выполнения инициализации членов - отсутствуют "пустые" конструкторы, необходимые при наследовании... (и не только из-за этого :) ) А если вернуться к вопросу выбора метода ("оптимального" - как я все время "просил" :) ) доступа к функциям класса, то в каждом конкретном случае он свой! В одном случае "хватает" static, а в другом необходима перегружаемая virtual функция.. :) Универсального решения не бывает! Еще раз спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться