![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Alek86 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
Вопрос для тех, кто читал книгу "Новые сложные задачи по С++" Герба Саттера.
В своей задаче №18 "Виртуальность" он привел пример правильного, по его мнению использования виртуальных функций:
но я (на теперешний момент) с ним абсолютно не согласен (понимаю, заява та еще...), потому что тогда для класса Widget нельзя будет написать отакой интерфейс, к примеру, для использования в паттерне, к примеру, Decorator.
ведь мне тогда легко может потребоваться сделать еще один вариант Widget'a, который будет включать и делегировать класс из примера 18-2. а если функции невиртуальные, то никакого делегирования не получится. Это мои соображения. Но авторитет автора подсказывает мне, что неправ я. Но в чем - не пойму. Может кто-нибудь объяснить чем именно, или дать ссылку на обсужения? |
||||
|
|||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
не совсем понял твою идею. вполне себе реализуется, тока не так как ты написал, а опятьже вызовом невиртуальных функций объекта класса widget Идея Саттера в том, что widget - это базовый класс, который полностью контролирует свой интерфейс, т.е. наследники не определяют никаких методов в секции public и тем самым любое введение или изменение, скажем, пред и пост условий делается в одном месте - в невиртуальной функции базового класса. Также, например,
показано, что реализация DoProcess может быть разделена на некие фазы, которые могут по разному реализовываться наследниками, но такое по ведение с открытыми виртуальными функциями усложнит интерфейс, а что более важно сильно усложнит использование такого интерфейса. |
||||
|
|||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
вроде понял.
поторопился я с вопросом спасибо. |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
хотя, уточню...
получается, что если мне потребуется создать класс Widget3steps, функция Process которого будет должна состоять из 3х шагов, то я этим способом не смогу никак использовать наработки из класса Widget? Ведь если я сделаю Widget3steps потомком класса Widget, то мне придется заместить функцию Process, то есть ни о каком полиморфизме не может быть и речи. из всего этого вывод, что прибегать к такому методу нужно только в случае, если Process будет 100% вызывать 2 функции (к примеру), поскольку если все невиртуальные функции будут только делегировать виртуальные, то смысла в таком построении класса нет. |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
все не так. ничего замещать не нужно. Что значит из 3-х шагов? вопервых шагов может быть сколько угодно и их количество определяется базовым классом, во вторых главная идея такого подхода - разделение интерфейса и реализации. Ведь ничто тебе не препятствует в потомке Widget3steps написать просто третью функцию и вызвать ее в реализации 2-го шага , а если это невозможно, то видимо имеем ошибку проектирования - ибо тогда и с открытыми виртуальными функциями будем иметь проблемы, так как вызовы для потомков видимо будут разные и полиморфно через интерфейс родителя работать будет невозможно. Опять же если нам вдруг понадобился в каком-то одном потомке 3-й шаг, то добавляем в родителе вызов 3-й виртуальной функции, которая ничего не делает и переопределяем ее только в том классе, которому она требуется и на интерфейсе и полиморфном использовании нашей иерархии это никак не скажется. даже если будут только делегировать виртуальные - есть. Хотябы просто с точки зрения отладки и сопровождения потому, что поддерживать и контролировать интерфейс нужно будет только в родительском классе, а не во всех его потомках |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
хорошие объяснения, спасибо.
но еще непонятка: Все-таки не очень смог представить, как реализовать декоратор ведь для него требуется, чтобы были: 1. интерфейс - он у нас есть 2. возможность наследникам интерфейса включать "экземпляр" этого-же самого интерфейса и делегировать его функции. А вот тут проблемы, так как я не смогу сделегировать никакие виртуальные функции (которые, по сути, и будут "рабочей" частью класса). Вызвать публичные функции (невиртуальные) я смогу, но где?! Но почему именно невиртуальными функциями? Чтоб поставить "заглушку"? Ведь если будет все точно также, но публичные будут виртуальными, то проблем с включением не будет. |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
честно говоря не втыркаю в твою терминологию. Может быть мы по разному понимаем паттерн Decorator, но я не вижу никакой проблемы. Ведь наш декоратор является наследником и переопределение в нем виртуальных функций ничем не ограничено, а работать он будет как любой другой наследник через интерфейс родителя
Добавлено @ 18:22 не понимаю твою мысль. Что означает "включение" и честно говоря не вижу никаких проблем. Переопределяй как хочешь свои виртальные функции в наследниках. Единственное отличие (оно же преимущество) в том, что выбор конкретной виртуальной функции будет происходить не в месте использования твоего экземпляра класса, когда ты вызываешь метод интерфейса, а внутри невиртуальной функции родителя, которая этот интерфейс определяет. Это сообщение отредактировал(а) Fazil6 - 9.10.2007, 18:34 |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
и, если Process( Gadget& G ) вызывает 2 виртуальные функции DoProcessPhasel( Gadgets ) и DoProcessPhase2( Gadget& ), то вызывать wid->Process(G) (из твоего примера) в первой из них?
да, тогда проблем особо нет, если в Process( Gadget& G ) очень простая логика, без if'ов. под термином "включение" я подразумевал ту самую альтенативу наследованию, которую все, кому не лень, рекомендуют использовать в большинстве случаев (и не зря). Забыл, как оно правильно зовется |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
а какая разница? Мы ведь говорим о конкретном паттерне Decorator, а его смысл это передать вызов метода интерфейса реальному экземпляру и добавить что-то еще свое. Т.е. даже если рассматривать в качестве примера код из Саттера с вызовами 2-х шагов, то для декоратора здесь по барабану эта логика. По логике работы интерфейса widget и логике паттерна отработают виртуальные функции экземпляра, который декоратор хранит, а в какой из виртуальных функций декоратора его теребить, тут уж от конкретной задачи зависит...
по своей сути невиртуальный интерфейс просто добавляет еще один вызов функции без добавления бизнеса и поэтому сами функции в интерфейсе класса обычно очень простые. Как правило там просто вызов непаблик виртуальной функции и все. а, ты про композицию... Мне становится ясна твоя мысль. Только не совсем понимаю почему ты решил, что ты должен делегировать именно виртуальные функции при композиции вместо наследования. Делегировать нужно функции открытого интерфейса , а виртуальные они или нет , кого это колышет? Какая тебе разница когда ты вызываешь функцию у объекта виртуальная она или нет? |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
да уж, тут у меня прокол.
и хотя уж очень не нравится, что нужно "засорять" DoProcessPhasel( Gadgets ) в начале вызовом wid->Process(G), зато, вроде, все стало на свои места... спасибо, щас плюсану Добавлено через 1 минуту и 35 секунд думаю, вопрос решен |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |