![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Это вроде композицией называется. На примере сериализации. От этого класса есть какое-то количество наследников, которые все нужно сериализовать. Ошибочно реализовывать метод сериализации для каждого наследника, вместо этого создается один метод сериализации, но с аргументом не какого-либо наследника, а их родителя. Тогда в такой метод можно передавать любого наследника. Вопрос: в таком случае доступ к свойствам и методам наследника будет? Ведь наследник - это свойства\методы родителя + свои, наследник передается через аргумент с типом его родителя, то есть, свойства\методы наследника не доступны.. Или я ошибаюсь?
|
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
нет, не это. имхо, или не так описали, или не так поняли.
либо базовый класс должен обладать необходимым интерфейсом, либо нужно привести базу к типу наследника. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
ага, писал по памяти. Сейчас найти ту информацию не могу. Нечто вроде:
Вопрос: в таком варианте добавочные свойства\методы наследников Dog, Cat,.., N не доступны, раз они передаются по типу Pet? И если не доступны, как сделать так, чтобы были доступны и при этом сохранить такой тип аргумента, чтобы не реализовывать метод для каждого наследника? |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
"обычный" полиморфизм двойная диспатчеризация (она же паттерн визитер) dynamic_cast |
|||
|
||||
| KelTron |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 745 Регистрация: 8.10.2006 Где: Красноярск Репутация: нет Всего: 38 |
Так если у тебя логика функции отличается для разных типов объектов, то так и надо сделать для каждого типа свою функцию.
Ссылка на базовый класс имеет смысл только тогда, когда со всеми потомками можно работать как с базовым классом, т.е. требуется только унаследованный интерфейс. -------------------- Тысячами незримых нитей обвивает тебя Закон. Разрубишь одну - преступник. Десять - смертник. Все - Бог. Эвенгар Салладорский, основатель Школы Тьмы. |
|||
|
||||
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
про обычный полиморфизм не понял, как это возможно, может быть вы имеете ввиду виртуализацию? по остальному - гуглю.
Само собой логика одна и та же, поэтому плодить метод бессмысленно, а как правильно - не знаю. |
||||
|
|||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
тогда тоже в гугль (или сразу в книжку) - динамический полиморфизм
ну для начала приведите пример более точно отражающий вашу задачу, чем пример выше. |
||||
|
|||||
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Я про виртуальные функции и говорил.
Пример привести не могу, т.к. конкретной задачи нет. Интересовало вот что: если мы передаем в функцию с параметром типа Родитель аргумент с типом ПотомокЭтогоРодителя, то в функции у нас будет доступ к свойствам и методам потомка или только к унаследованным от Родителя?
Это сообщение отредактировал(а) Gunslinger - 19.11.2009, 09:36 |
||||
|
|||||
| KelTron |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 745 Регистрация: 8.10.2006 Где: Красноярск Репутация: нет Всего: 38 |
Только к унаследованным, хотя можно сделать явное приведение, но тогда полностью теряется смысл в ссылке на базовый класс. -------------------- Тысячами незримых нитей обвивает тебя Закон. Разрубишь одну - преступник. Десять - смертник. Все - Бог. Эвенгар Салладорский, основатель Школы Тьмы. |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ну вот Вам тогда общие примеры, может поможет наглядно разобраться: http://forum.vingrad.ru/index.php?showtopi...t&p=1715082 http://forum.vingrad.ru/index.php?showtopi...t&p=1692823 (ну вот пришлось вместо Вас поиск пользовать... Это сообщение отредактировал(а) mes - 19.11.2009, 14:32 |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
mes, извините, что отнял столько времени с поиском - я в гугле искал, а по форуму поискать не додумался.
Читаю ссылки, что вы дали. Понял, что в понимании низкого уровня пробел. Пока другой вопрос: про указатели и адреса памяти. Какой смысл писать тип указателя, тем более структуры или класса? Указатель же хранит адрес ячейки памяти, а структура\класс со своими полями\методами занимает больше, чем одна ячейка... Или эта инфа для компилятора? з.ы. под ячейкой я понимаю 1 байт. Это сообщение отредактировал(а) Gunslinger - 19.11.2009, 16:36 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ну искать не долго то было.. я то знал что ищу.. замечание было направлено на то, чтоб обратить внимание , что многие темы поднимались и разбирались уже не раз и даже с примерами. Добавлено через 5 минут и 29 секунд Да.. но не только для компилятора, но и для удобства программиста. Это сообщение отредактировал(а) mes - 19.11.2009, 16:56 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
нет указатель нечто больше.. адрес то можно хранить и в void *, но тогда статическая информация о типе (в частности об интерфейсе доступа к объекту) будет утеряна. Ну взять хотя бы инкрементацию указателя.. Она изменяет его значение не на один байт, а на размер объекта типа. P.S. не забывайте про правило форума :один вопрос - одна тема. Это сообщение отредактировал(а) mes - 19.11.2009, 17:13 |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Понял, создал отдельную: "Механика работы указателей" -- http://forum.vingrad.ru/forum/act-ST/f-92/...0/unread-1.html Это сообщение отредактировал(а) Gunslinger - 20.11.2009, 10:37 |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Тип это некая абстракция языка позволяющая определить поведение объектов и взаимодействие между ними.
C++ обладает статической типизацией, т.е. вся информация о типах существует только в режиме компиляции. Типы бывают встроенными (int, double...) и пользовательскими (struct, class, union). Тип переменной проассоциирован с ней на протяжении всей ее видимости. т.е. программист пишет int i; и в дальнейшем везде где используется эта i компилятор знает, что она int. Благодаря типизации возможна перегрузка функций. Т.е. вызывая какую нибудь функцию с аргументами компилятор ищет из всех функций с одинаковым именем, наиболее подходящую. Польза от перегрузки очевидная:
В C++ перегрузка существует не только для функций, но и для операторов. т.е. в выражении a+b; выберется к примеру op+<int, int>() или op+<double,double>() Однако одной перегрузки нeдостаточно для удобной работы, так как нам пришлось бы определять кучу одинаковых функций для всех нужных типов. Для решения этой проблемы в c++ введено приведение типов. (Оно бывает явное и неявное, а также делится по уровням продвижение, стандарное и пользовательское преобразования). теперь для выражения char_+int_ не нужно реализовывать отдельный плюс, а можно привести к виду int_ + int_. То же касается и пользовательских типов, для которых программист может определить нужные преобразования. Также благодаря знаниям o типе известен и размер объекта, и нам не нужно следить вручную. По типам вроде бы все, пойдем дальше.. Чтоб работать с объектом в С++ существуют временный объект, переменная, ссылка, и указатель. Каждая это представление (еще одно помимо типа) некой абстракции для пользования объектом. Указатель это такой объект, который хранит адрес другого объекта или 0, позволяет итерацию (размер шага которой определяется типом указателя), а также предоставляет доступ путем разъименования или через operator->() Ссылка это сущность (не объект) которая проассоциирована с адресом объекта и предоставляет к нему доступ посредством operator.() Ну кажется все.. Надеюсь объяснение не сильно отличается от истины |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
mes,
здесь не понял, моли бы вы пояснить? |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
ну Вы же уже сами сказали : или Вы про шаг ? объясните себе почему в этом примере вычисления дают разный результат :
|
|||
|
||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Gunslinger,
Динамический полиморфизм. Мне больше нравится пример иерархии графических объектов с функцией рисования объекта. В С++ реализуется посредством виртуальных функций.
поскольку вызывается функция, реализуемая в конкретном классе-наследнике, ей известно и какого типа объект, и есть доступ к переменным класса. |
||||
|
|||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
В переменной, на которую указывает р кладется сумма адреса i+1, затем выводится их разница. А вот потом не понял. Зачем приводить адреса к int? Они и так int. Что значит эта запись с технической стороны? Создается переменная с размером Shape, она инициализируется размером Circle. Куда компилятор денет свойства\методы, которые не поместятся в размер Shape? |
|||
|
||||
| mes |
|
||||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
если это так, то почему разный результат ? Вы пробовали запускать ?
Эта запись состоит из двух частей : правая - это создание нового объекта (т.е. выделение памяти и инициализация ее в связи с требованием к объекту). левая - это определение указателя инициализированного в данном случае адресом новосозданного объекта.
Методы описаны в классе, но не существуют в объекте. Память при создании объекта выделяется только под его дата-члены (в том числе и под служебные данные в некоторых случаях) То что методы описываются внутри класса это всего лишь особенность С++, фактически нужная для того, чтоб был определен class scope функции, а также права доступа. |
||||||
|
|||||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Gunslinger, Вам имхо не технической стороной интересоваться надо, а семантикой языка. Ибо язык высокого уровня разрабатывается для того, что бы абстрагироваться от технических деталей, а реализация может быть разная.
в динамической памяти (при помощи оператора new) создается объект типа Circle. Естественно, размером sizeof (Circle). указатель на этот объект помещается в переменную p типа указатель на Shape. Это вполне законно, т.к. Circle наследует Shape. При обращении к виртуальным методам класса Shape типа p->draw() будет вызываться функция не из класса Shape, а из Circle (технически это реализуется компилятором через таблицу виртуальных функций vtable, но для программиста этот факт совершенно не важен). Таким образом язык реализует динамический полиморфизм - одну из своих ключевых концепций. Иными словами программист обращается с указателем p как с указателем на Shape, вызывая разные методы. Объект при этом ведет себя в зависимости от реального типа объекта, на который указывает p. В некоторых (редких) случаях, когда требуется привести указатель на объект базового класса к производному, используется dynamic_cast<>, но в подавляющем большинстве ситуаций полиморфизма достаточно. Еще раз повторю: p - указатель, хранит адрес памяти, его размер не связан с конкретным типом объекта (теоретически он может быть неодинаковым для разных способов размещения, в т.ч. зависящих от типа, это учитывается в стандарте, но на практике таких случаев мне неизвестно.) ЗЫ: Мы не можем корректно сделать копию объекта, имея только указатель базового класса, не прибегая к разным хитростям именно потому , что размер реального объекта неизвестен. Если подобное требуется, обычно реализуют в классе виртуальный метод clone(). Добавлено через 9 минут и 50 секунд Gunslinger, почитайте таки про арифметику указателей. тут например. |
||||
|
|||||
| Gunslinger |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Наконец установил компилятор и проверил. Первый вычет действительно возвращает разницу в 1, а второй - 4. Получается, первый вычет это как бы высокоуровневое значение, а второй - типа sizeof, количество байт. А было похоже на приведение типа. |
||||
|
|||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
нет .. в первом случае арифметика указателей, и считается сколько штук объектов (int) может поместиться, а во втором обычная числовая математика, и показывает на сколько единиц отличаются значения, также 3й вариант (char*)p - (char*)&i - тоже арифметика указателей, но так как объект в данном случае char (1 байтовый), можно принять, что считает разницу в байтах. Вот для того чтоб компилятор знал, чего программист от него хочет и нужна типизация. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
mes, не могу понять это: (int)&i и (char*)&i. Само приведение понятно: удаляются\добавляются недостающие\избыточные байты до нужного типа, адрес остается тот же. Т.е. работа с кусками памяти (ячейками). А тут операция приведения применяется к адресам ячеек, а не к самим ячейкам. А адрес - это номер всего лишь первого байта...
Могли бы вы разъяснить? |
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Gunslinger, никакие байты (в данном случае) не удаляются. есть числовое значение (адрес), изменяется лишь его семантика (смысл) и, соответственно, способ его использования.
|
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Какие байты удаляются ?! Приведение к типу это не удаление, а просто смена взгляда. давайте на абстрактных примерах: у Вас есть ящик, в нем 12 коробок в каждом из которых 10 яблок. представим ящик как коробки, сколько их ? // 12 представим коробку как апельсины, сколько их ? // 10 представим ящик как апельсины, сколько их ? // 120 обратили внимание что один и тот же вопрос "сколько их?" несет разный ответ в зависимости от контекста, то есть для каждого разбираемого типа у нас есть свой способ подсчета кол-ва сущностей, т.е у нас есть несколько перегруженных функций "сколько" и есть аргумент "их" который принимал у нас в задаче разные типы. а выражениe "представим как" - есть преобразование типа, как видите никакие апельсины никогда никуда не удалялись, даже когда мы рассматривали одну коробку, они просто терялись из виду. пока все .. чуть позже разберем пример из предыдущего поста . |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
baldina,
mes, да, сказал не корректно. Так, может, лучше: при приведении меняется тип и, соответственно, размер ячейки; все, что не попало в новый тип(размер) - остается "за бортом". mes, вроде аналог коробок.. Это сообщение отредактировал(а) Gunslinger - 3.12.2009, 17:36 |
|||
|
||||
| mes |
|
||||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
да при чем тут вообще размер ячейки ? смена типа не обязательно влияет на размер. для начала вот Вам пример, объясните результат :
Это сообщение отредактировал(а) mes - 3.12.2009, 18:36 |
||||
|
|||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
mes, может быть потому, что типы разные? Хранящийся float компилятор выводит как int. Больше вариантов нет.
|
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
угу, не смотря на то что в битовом представлении обе сущности идентичны, взаимодействие с ними происходит по разному. Это определяет тип. Т.е. грубо говоря тип показывает не только (и не столько) сколько памяти требует объект, а как эту память трактовать, то есть какие действия и как с ней производить. На самом деле память вообще не причем, это всего лишь частный случай. Это сообщение отредактировал(а) mes - 4.12.2009, 14:10 |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
Спасибо за пример, доходчиво. Теперь осознал, что речь не только о количестве байт. Но, если это как-то связано с вопросами выше: (int)&i и (char*)&i, - то я все равно не догнал. Облазил гугл в поисках подобных примеров, но ничего не нашел - только приведение обычных переменных. |
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Gunslinger, см. выше, я же специально привел пример вычисдений с int и int*
|
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
Gunslinger, в каждом ящике 10 яблок, ответьте сколько яблок будет если увеличить на единицу 1. кол-во яблок 2. кол-во ящиков 3. вес яблока в граммах Теперь давайте посчитаем в десятках, 10,20,30,40 следующее 50 в сотнях 100, 200, 300, 400, следующее 500. Не смущает что слово "следующий " аналог ++ (+1) ? T.e. реальное действие зависит от контекста. Также и в арифметике указателей, при инкрементации адрес изменяется не на единицу, а на размер объекта. т.е. ++pint имеет смысл pint = (int*)( (char*) pint + sizeof(int) ); Это сообщение отредактировал(а) mes - 4.12.2009, 15:21 |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
baldina, читал. Пример понял, но вот что он мне должен был разъяснить касательно приведения- нет.
Сначала по ссылке baldina, а потом поисковика с прошлой недели изучаю все, что нашел про арифметику указателей. Так что этот момент я уже знаю. Вгоняют в ступор сами приведения со звездочками (int*, char* и т.п.). Без звездочек понятно... Или это указание компилятору, что приводятся не простые переменные, а указатели? |
|||
|
||||
| mes |
|
|||
|
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
звездочка означает указатель .. раньше был указатель на коробки (int*) , a привели к указателю на апельсины (char*) ведь точка отсчета у них одна и та же. При вычитании коробок (int*) считали сколько коробок (int) поместится. А при вычитании апельсинов (char*), считаем сколько поместится апельсинов (char). По этому в одном случае получили 1 , то есть одну коробку, а в другом 4, то есть 4 апельсина. для легкости представления , что в коробке апельсины располагается линейно в один ряд и что их в обсуждаемом случае вмещается 4 штуки в коробку. |
|||
|
||||
| Gunslinger |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 842 Регистрация: 30.12.2006 Где: Астрахань Репутация: 1 Всего: 3 |
||||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |